diff options
author | Andreas Eversberg <jolly@eversberg.eu> | 2023-04-23 12:05:44 +0200 |
---|---|---|
committer | laforge <laforge@osmocom.org> | 2023-07-17 12:29:42 +0000 |
commit | 2d27e2ccb10d9773d2d8bf5bfe6e8f08d34c7a7c (patch) | |
tree | 48d21da0ef15376c8e1cf53e3f1e55fce59af75d | |
parent | cd605f30b788ce1c5ad55ce650a830b8f9830dfe (diff) |
ASCI: Add functions to transcode VGCS/VBS messages on A-interface
Change-Id: I6b1f088201e7ef4a58762937855a1d358973882c
Related: OS#4854
-rw-r--r-- | include/osmocom/msc/ran_msg.h | 47 | ||||
-rw-r--r-- | src/libmsc/ran_msg.c | 19 | ||||
-rw-r--r-- | src/libmsc/ran_msg_a.c | 482 |
3 files changed, 548 insertions, 0 deletions
diff --git a/include/osmocom/msc/ran_msg.h b/include/osmocom/msc/ran_msg.h index 3e0ac6071..0dadd4f3a 100644 --- a/include/osmocom/msc/ran_msg.h +++ b/include/osmocom/msc/ran_msg.h @@ -69,6 +69,26 @@ enum ran_msg_type { RAN_MSG_HANDOVER_SUCCEEDED, RAN_MSG_HANDOVER_COMPLETE, RAN_MSG_HANDOVER_FAILURE, + RAN_MSG_VGCS_VBS_SETUP, + RAN_MSG_VGCS_VBS_SETUP_ACK, + RAN_MSG_VGCS_VBS_SETUP_REFUSE, + RAN_MSG_VGCS_VBS_ASSIGN_REQ, + RAN_MSG_VGCS_VBS_ASSIGN_RES, + RAN_MSG_VGCS_VBS_ASSIGN_FAIL, + RAN_MSG_VGCS_VBS_QUEUING_IND, + RAN_MSG_UPLINK_REQUEST, + RAN_MSG_UPLINK_REQUEST_ACK, + RAN_MSG_UPLINK_REQUEST_CNF, + RAN_MSG_UPLINK_APPLICATION_DATA, + RAN_MSG_UPLINK_RELEASE_IND, + RAN_MSG_UPLINK_REJECT_CMD, + RAN_MSG_UPLINK_RELEASE_CMD, + RAN_MSG_UPLINK_SEIZED_CMD, + RAN_MSG_VGCS_ADDITIONAL_INFO, + RAN_MSG_VGCS_VBS_AREA_CELL_INFO, + RAN_MSG_VGCS_VBS_ASSIGN_STATUS, + RAN_MSG_VGCS_SMS, + RAN_MSG_NOTIFICATION_DATA, }; extern const struct value_string ran_msg_type_names[]; @@ -270,6 +290,33 @@ struct ran_msg { } handover_failure; struct ran_handover_request handover_request; struct ran_handover_request_ack handover_request_ack; + struct gsm0808_vgcs_vbs_setup vgcs_vbs_setup; + struct gsm0808_vgcs_vbs_setup_ack vgcs_vbs_setup_ack; + struct { + enum gsm0808_cause cause; + } vgcs_vbs_setup_refuse; + struct gsm0808_vgcs_vbs_assign_req vgcs_vbs_assign_req; + struct gsm0808_vgcs_vbs_assign_res vgcs_vbs_assign_res; + struct gsm0808_vgcs_vbs_assign_fail vgcs_vbs_assign_fail; + struct gsm0808_uplink_request uplink_request; + struct gsm0808_uplink_request_ack uplink_request_ack; + struct gsm0808_uplink_request_cnf uplink_request_cnf; + struct gsm0808_uplink_app_data uplink_app_data; + struct gsm0808_uplink_release_ind uplink_release_ind; + struct gsm0808_uplink_seized_cmd uplink_seized_cmd; + struct gsm0808_uplink_reject_cmd uplink_reject_cmd; + struct { + enum gsm0808_cause cause; + } uplink_release_cmd; + struct { + struct gsm0808_talker_identity talker_identity; + } vgcs_additional_info; + struct gsm0808_vgcs_vbs_area_cell_info vgcs_vbs_area_cell_info; + struct gsm0808_vgcs_vbs_assign_stat vgcs_vbs_assign_stat; + struct { + struct gsm0808_sms_to_vgcs sms_to_vgcs; + } vgcs_sms; + struct gsm0808_notification_data notification_data; }; }; diff --git a/src/libmsc/ran_msg.c b/src/libmsc/ran_msg.c index 11564d8fc..14f250d2f 100644 --- a/src/libmsc/ran_msg.c +++ b/src/libmsc/ran_msg.c @@ -51,6 +51,25 @@ const struct value_string ran_msg_type_names[] = { { RAN_MSG_HANDOVER_DETECT, "HANDOVER_DETECT" }, { RAN_MSG_HANDOVER_COMPLETE, "HANDOVER_COMPLETE" }, { RAN_MSG_HANDOVER_FAILURE, "HANDOVER_FAILURE" }, + { RAN_MSG_VGCS_VBS_SETUP, "VGCS_VBS_SETUP" }, + { RAN_MSG_VGCS_VBS_SETUP_ACK, "VGCS_VBS_SETUP_ACK" }, + { RAN_MSG_VGCS_VBS_SETUP_REFUSE, "VGCS_VBS_SETUP_REFUSE" }, + { RAN_MSG_VGCS_VBS_ASSIGN_REQ, "VGCS_VBS_ASSIGN_REQ" }, + { RAN_MSG_VGCS_VBS_ASSIGN_RES, "VGCS_VBS_ASSIGN_RES" }, + { RAN_MSG_VGCS_VBS_ASSIGN_FAIL, "VGCS_VBS_ASSIGN_FAIL" }, + { RAN_MSG_VGCS_VBS_QUEUING_IND, "VGCS_VBS_QUEUING_IND" }, + { RAN_MSG_UPLINK_REQUEST, "UPLINK_REQUEST" }, + { RAN_MSG_UPLINK_REQUEST_ACK, "UPLINK_REQUEST_ACK" }, + { RAN_MSG_UPLINK_REQUEST_CNF, "UPLINK_REQUEST_CNF" }, + { RAN_MSG_UPLINK_APPLICATION_DATA, "UPLINK_APPLICATION_DATA" }, + { RAN_MSG_UPLINK_RELEASE_IND, "UPLINK_RELEASE_IND" }, + { RAN_MSG_UPLINK_REJECT_CMD, "UPLINK_REJECT_CMD" }, + { RAN_MSG_UPLINK_RELEASE_CMD, "UPLINK_RELEASE_CMD" }, + { RAN_MSG_UPLINK_SEIZED_CMD, "UPLINK_SEIZED_CMD" }, + { RAN_MSG_VGCS_ADDITIONAL_INFO, "VGCS_ADDITIONAL_INFO" }, + { RAN_MSG_VGCS_VBS_AREA_CELL_INFO, "VGCS_VBS_AREA_CELL_INFO" }, + { RAN_MSG_VGCS_VBS_ASSIGN_STATUS, "VGCS_VBS_ASSIGN_STATUS" }, + { RAN_MSG_VGCS_SMS, "VGCS_SMS" }, {} }; diff --git a/src/libmsc/ran_msg_a.c b/src/libmsc/ran_msg_a.c index c49adf474..570a8d1ed 100644 --- a/src/libmsc/ran_msg_a.c +++ b/src/libmsc/ran_msg_a.c @@ -742,6 +742,438 @@ static int ran_a_decode_handover_failure(struct ran_dec *ran_dec, const struct m return ran_decoded(ran_dec, &ran_dec_msg); } +static int ran_a_decode_vgcs_vbs_setup_ack(struct ran_dec *ran_dec, const struct msgb *msg, const struct tlv_parsed *tp) +{ + struct ran_msg ran_dec_msg = { + .msg_type = RAN_MSG_VGCS_VBS_SETUP_ACK, + .msg_name = "BSSMAP VGCS/VBS SETUP ACKNOWLEDGE", + }; + struct gsm0808_vgcs_vbs_setup_ack *r = &ran_dec_msg.vgcs_vbs_setup_ack; + int rc; + + const struct tlv_p_entry *ie_flags = TLVP_GET(tp, GSM0808_IE_VGCS_FEATURE_FLAGS); + + /* VGCS Feature Flags, 3.2.2.88 */ + if (ie_flags) { + rc = gsm0808_dec_vgcs_feature_flags(&r->flags, ie_flags->val, ie_flags->len); + if (rc < 0) { + LOG_RAN_A_DEC_MSG(LOGL_ERROR, "Unable to decode VGCS/VBS Feature Flags\n"); + return -EINVAL; + } + r->vgcs_feature_flags_present = true; + } + + return ran_decoded(ran_dec, &ran_dec_msg); +} + +static int ran_a_decode_vgcs_vbs_setup_refuse(struct ran_dec *ran_dec, const struct msgb *msg, + const struct tlv_parsed *tp) +{ + struct ran_msg ran_dec_msg = { + .msg_type = RAN_MSG_VGCS_VBS_SETUP_REFUSE, + .msg_name = "BSSMAP VGCS/VBS SETUP REFUSE", + }; + + const struct tlv_p_entry *ie_cause = TLVP_GET(tp, GSM0808_IE_CAUSE); + + /* Cause, 3.2.2.5 */ + if (!ie_cause || ie_cause->len < 1) { + LOG_RAN_A_DEC_MSG(LOGL_ERROR, "Mandatory IE missing: Cause\n"); + return -EINVAL; + } + ran_dec_msg.vgcs_vbs_setup_refuse.cause = ie_cause->val[0]; + + return ran_decoded(ran_dec, &ran_dec_msg); +} + +static int ran_a_decode_vgcs_vbs_assign_res(struct ran_dec *ran_dec, const struct msgb *msg, + const struct tlv_parsed *tp) +{ + struct ran_msg ran_dec_msg = { + .msg_type = RAN_MSG_VGCS_VBS_ASSIGN_RES, + .msg_name = "BSSMAP VGCS/VBS ASSIGNMENT RESULT", + }; + struct gsm0808_vgcs_vbs_assign_res *r = &ran_dec_msg.vgcs_vbs_assign_res; + int rc; + + const struct tlv_p_entry *ie_channel_type = TLVP_GET(tp, GSM0808_IE_CHANNEL_TYPE); + const struct tlv_p_entry *ie_cell_id = TLVP_GET(tp, GSM0808_IE_CELL_IDENTIFIER); + const struct tlv_p_entry *ie_chosen_channel = TLVP_GET(tp, GSM0808_IE_CHOSEN_CHANNEL); + const struct tlv_p_entry *ie_cic = TLVP_GET(tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE); + const struct tlv_p_entry *ie_circuit_pool = TLVP_GET(tp, GSM0808_IE_CIRCUIT_POOL); + const struct tlv_p_entry *ie_aoip = TLVP_GET(tp, GSM0808_IE_AOIP_TRASP_ADDR); + const struct tlv_p_entry *ie_call_id = TLVP_GET(tp, GSM0808_IE_CALL_ID); + + /* Channel Type, 3.2.2.11 */ + if (!ie_channel_type) { + LOG_RAN_A_DEC_MSG(LOGL_ERROR, "Mandatory IE missing: Channel Type\n"); + return -EINVAL; + } + if (gsm0808_dec_channel_type(&r->channel_type, ie_channel_type->val, ie_channel_type->len) <= 0) { + LOG_RAN_A_DEC_MSG(LOGL_ERROR, "Failed to decode Channel Type IE\n"); + return -EINVAL; + } + + /* Cell Identifier, 3.2.2.17 */ + if (!ie_cell_id) { + LOG_RAN_A_DEC_MSG(LOGL_ERROR, "Mandatory IE missing: Cell Identifier\n"); + return -EINVAL; + } + rc = gsm0808_dec_cell_id(&r->cell_identifier, ie_cell_id->val, ie_cell_id->len); + if (rc < 0) { + LOG_RAN_A_DEC_MSG(LOGL_ERROR, "Decoding Cell Identifier gave rc=%d\n", rc); + return -EINVAL; + } + + /* Chosen Channel, 3.2.2.33 */ + if (ie_chosen_channel) { + r->chosen_channel = ie_chosen_channel->val[0]; + r->chosen_channel_present = true; + } + + /* Circuit Identity Code, 3.2.2.2 */ + if (ie_cic) { + if (ie_cic->len != 2) { + LOG_RAN_A_DEC_MSG(LOGL_ERROR, "Circuit Identity Code has invalid length.\n"); + return -EINVAL; + } + r->cic = *(uint16_t *)ie_cic->val; + r->cic_present = true; + } + + /* Circuit Pool, 3.2.2.45 */ + if (ie_circuit_pool) { + r->circuit_pool = ie_circuit_pool->val[0]; + r->circuit_pool_present = true; + } + + /* AoIP Transport Layer Address (BSS), 3.2.2.102 */ + if (ie_aoip) { + if (gsm0808_dec_aoip_trasp_addr(&r->aoip_transport_layer, ie_aoip->val, ie_aoip->len) < 0) { + LOG_RAN_A_DEC_MSG(LOGL_ERROR, "unable to decode AoIP transport address\n"); + return -EINVAL; + } + r->aoip_transport_layer_present = true; + } + + if (ie_call_id) { + if (ie_call_id->len != 4) { + LOG_RAN_A_DEC_MSG(LOGL_ERROR, "Call Identifier has invalid length.\n"); + return -EINVAL; + } + r->call_id = osmo_load32le(ie_call_id->val); + r->call_id_present = true; + } + + return ran_decoded(ran_dec, &ran_dec_msg); +} + +static int ran_a_decode_vgcs_vbs_assign_fail(struct ran_dec *ran_dec, const struct msgb *msg, + const struct tlv_parsed *tp) +{ + struct ran_msg ran_dec_msg = { + .msg_type = RAN_MSG_VGCS_VBS_ASSIGN_FAIL, + .msg_name = "BSSMAP VGCS/VBS ASSIGNMENT FAILURE", + }; + struct gsm0808_vgcs_vbs_assign_fail *r = &ran_dec_msg.vgcs_vbs_assign_fail; + int rc; + + const struct tlv_p_entry *ie_cause = TLVP_GET(tp, GSM0808_IE_CAUSE); + const struct tlv_p_entry *ie_circuit_pool = TLVP_GET(tp, GSM0808_IE_CIRCUIT_POOL); + const struct tlv_p_entry *ie_circuit_pool_list = TLVP_GET(tp, GSM0808_IE_CIRCUIT_POOL_LIST); + const struct tlv_p_entry *ie_codec_list_bss_supported = TLVP_GET(tp, GSM0808_IE_SPEECH_CODEC_LIST); + + /* Cause, 3.2.2.5 */ + if (!ie_cause || ie_cause->len < 1) { + LOG_RAN_A_DEC_MSG(LOGL_ERROR, "Mandatory IE missing: Cause\n"); + return -EINVAL; + } + r->cause = ie_cause->val[0]; + + /* Circuit Pool, 3.2.2.45 */ + if (ie_circuit_pool) { + r->circuit_pool = ie_circuit_pool->val[0]; + r->circuit_pool_present = true; + } + + /* Circuit Pool List, 3.2.2.46 */ + if (ie_circuit_pool_list && ie_circuit_pool_list->len) { + if (ie_circuit_pool_list->len > CIRCUIT_POOL_LIST_MAXLEN) { + LOG_RAN_A_DEC_MSG(LOGL_ERROR, "Circuit Pool List has invalid length.\n"); + return -EINVAL; + } + memcpy(r->cpl.pool, ie_circuit_pool_list->val, ie_circuit_pool_list->len); + r->cpl.list_len = ie_circuit_pool_list->len; + r->cpl_present = true; + } + + /* Codec List (BSS Supported) 3.2.2.103 */ + if (ie_codec_list_bss_supported) { + rc = gsm0808_dec_speech_codec_list(&r->codec_list_bss_supported, + ie_codec_list_bss_supported->val, ie_codec_list_bss_supported->len); + if (rc < 0) { + LOG_RAN_A_DEC_MSG(LOGL_ERROR, + "Complete Layer 3 Information: unable to decode IE Codec List (BSS Supported)" + " (rc=%d), continuing anyway\n", rc); + /* This IE is not critical, do not abort with error. */ + } else + r->codec_list_present = true; + } + + return ran_decoded(ran_dec, &ran_dec_msg); +} + +static int ran_a_decode_vgcs_vbs_queuing_ind(struct ran_dec *ran_dec, const struct msgb *msg, + const struct tlv_parsed *tp) +{ + struct ran_msg ran_dec_msg = { + .msg_type = RAN_MSG_VGCS_VBS_QUEUING_IND, + .msg_name = "BSSMAP VGCS/VBS QUEUING INDICATION", + }; + + return ran_decoded(ran_dec, &ran_dec_msg); +} + +static int ran_a_decode_uplink_request(struct ran_dec *ran_dec, const struct msgb *msg, const struct tlv_parsed *tp) +{ + struct ran_msg ran_dec_msg = { + .msg_type = RAN_MSG_UPLINK_REQUEST, + .msg_name = "BSSMAP UPLINK REQUEST", + }; + struct gsm0808_uplink_request *r = &ran_dec_msg.uplink_request; + int rc; + + const struct tlv_p_entry *ie_talker_priority = TLVP_GET(tp, GSM0808_IE_TALKER_PRIORITY); + const struct tlv_p_entry *ie_cell_id = TLVP_GET(tp, GSM0808_IE_CELL_IDENTIFIER); + const struct tlv_p_entry *ie_l3_info = TLVP_GET(tp, GSM0808_IE_LAYER_3_INFORMATION); + const struct tlv_p_entry *ie_mi = TLVP_GET(tp, GSM0808_IE_MOBILE_IDENTITY); + + /* Talker Priority, 3.2.2.89 */ + if (ie_talker_priority) { + r->talker_priority = ie_talker_priority->val[0] & 0x03; + r->talker_priority_present = true; + } + + /* Cell Identifier, 3.2.2.17 */ + if (ie_cell_id) { + rc = gsm0808_dec_cell_id(&r->cell_identifier, ie_cell_id->val, ie_cell_id->len); + if (rc < 0) { + LOG_RAN_A_DEC_MSG(LOGL_ERROR, "Decoding Cell Identifier gave rc=%d\n", rc); + return -EINVAL; + } + } + + /* Layer 3 Information, 3.2.2.24 */ + if (ie_l3_info && ie_l3_info->len) { + if (ie_l3_info->len > LAYER_3_INFORMATION_MAXLEN) { + LOG_RAN_A_DEC_MSG(LOGL_ERROR, "Call Identifier has invalid length.\n"); + return -EINVAL; + } + memcpy(r->l3.l3, ie_l3_info->val, ie_l3_info->len); + r->l3.l3_len = ie_l3_info->len; + r->l3_present = true; + } + + /* Mobile Identity, 3.2.2.41 */ + if (ie_mi) { + if (osmo_mobile_identity_decode(&r->mi, ie_mi->val, ie_mi->len, false)) { + LOG_RAN_A_DEC_MSG(LOGL_ERROR, "Decoding Mobile Identity gave rc=%d\n", rc); + return -EINVAL; + } + r->mi_present = true; + } + + return ran_decoded(ran_dec, &ran_dec_msg); +} + +static int ran_a_decode_uplink_request_cnf(struct ran_dec *ran_dec, const struct msgb *msg, const struct tlv_parsed *tp) +{ + struct ran_msg ran_dec_msg = { + .msg_type = RAN_MSG_UPLINK_REQUEST_CNF, + .msg_name = "BSSMAP UPLINK REQUEST CONFIRM", + }; + struct gsm0808_uplink_request_cnf *r = &ran_dec_msg.uplink_request_cnf; + int rc; + + const struct tlv_p_entry *ie_cell_id = TLVP_GET(tp, GSM0808_IE_CELL_IDENTIFIER); + const struct tlv_p_entry *ie_talker_identity = TLVP_GET(tp, GSM0808_IE_TALKER_IDENTITY); + const struct tlv_p_entry *ie_l3_info = TLVP_GET(tp, GSM0808_IE_LAYER_3_INFORMATION); + + /* Cell Identifier, 3.2.2.17 */ + if (!ie_cell_id) { + LOG_RAN_A_DEC_MSG(LOGL_ERROR, "Mandatory IE missing: Cell Identifier\n"); + return -EINVAL; + } + rc = gsm0808_dec_cell_id(&r->cell_identifier, ie_cell_id->val, ie_cell_id->len); + if (rc < 0) { + LOG_RAN_A_DEC_MSG(LOGL_ERROR, "Decoding Cell Identifier gave rc=%d\n", rc); + return -EINVAL; + } + + /* Talker Identity, 3.2.2.91 */ + if (ie_talker_identity) { + rc = gsm0808_dec_talker_identity(&r->talker_identity, ie_talker_identity->val, ie_talker_identity->len); + if (rc < 0) { + LOG_RAN_A_DEC_MSG(LOGL_ERROR, "Decoding Talker Identity gave rc=%d\n", rc); + return -EINVAL; + } + r->talker_identity_present = true; + } + + /* Layer 3 Information, 3.2.2.24 */ + if (!ie_l3_info) { + LOG_RAN_A_DEC_MSG(LOGL_ERROR, "Mandatory IE missing: Layer 3 Information\n"); + return -EINVAL; + } + if (ie_l3_info->len > LAYER_3_INFORMATION_MAXLEN) { + LOG_RAN_A_DEC_MSG(LOGL_ERROR, "Call Identifier has invalid length.\n"); + return -EINVAL; + } + memcpy(r->l3.l3, ie_l3_info->val, ie_l3_info->len); + r->l3.l3_len = ie_l3_info->len; + + return ran_decoded(ran_dec, &ran_dec_msg); +} + +static int ran_a_decode_uplink_application_data(struct ran_dec *ran_dec, const struct msgb *msg, + const struct tlv_parsed *tp) +{ + struct ran_msg ran_dec_msg = { + .msg_type = RAN_MSG_UPLINK_APPLICATION_DATA, + .msg_name = "BSSMAP UPLINK APPLICATION DATA", + }; + struct gsm0808_uplink_app_data *r = &ran_dec_msg.uplink_app_data; + int rc; + + const struct tlv_p_entry *ie_cell_id = TLVP_GET(tp, GSM0808_IE_CELL_IDENTIFIER); + const struct tlv_p_entry *ie_l3_info = TLVP_GET(tp, GSM0808_IE_LAYER_3_INFORMATION); + const struct tlv_p_entry *ie_app_data = TLVP_GET(tp, GSM0808_IE_APP_DATA); + + /* Cell Identifier, 3.2.2.17 */ + if (!ie_cell_id) { + LOG_RAN_A_DEC_MSG(LOGL_ERROR, "Mandatory IE missing: Cell Identifier\n"); + return -EINVAL; + } + rc = gsm0808_dec_cell_id(&r->cell_identifier, ie_cell_id->val, ie_cell_id->len); + if (rc < 0) { + LOG_RAN_A_DEC_MSG(LOGL_ERROR, "Decoding Cell Identifier gave rc=%d\n", rc); + return -EINVAL; + } + + /* Layer 3 Information, 3.2.2.24 */ + if (!ie_l3_info) { + LOG_RAN_A_DEC_MSG(LOGL_ERROR, "Mandatory IE missing: Layer 3 Information\n"); + return -EINVAL; + } + if (ie_l3_info->len > LAYER_3_INFORMATION_MAXLEN) { + LOG_RAN_A_DEC_MSG(LOGL_ERROR, "Call Identifier has invalid length.\n"); + return -EINVAL; + } + memcpy(r->l3.l3, ie_l3_info->val, ie_l3_info->len); + r->l3.l3_len = ie_l3_info->len; + + /* Application Data Information, 3.2.2.100 */ + if (!ie_app_data || ie_app_data->len < 1) { + LOG_RAN_A_DEC_MSG(LOGL_ERROR, "Mandatory IE missing: Application Data Information\n"); + return -EINVAL; + } + r->bt_ind = ie_app_data->val[0] & 0x01; + + return ran_decoded(ran_dec, &ran_dec_msg); +} + +static int ran_a_decode_uplink_release_ind(struct ran_dec *ran_dec, const struct msgb *msg, const struct tlv_parsed *tp) +{ + struct ran_msg ran_dec_msg = { + .msg_type = RAN_MSG_UPLINK_RELEASE_IND, + .msg_name = "BSSMAP UPLINK RELEASE INDICATION", + }; + struct gsm0808_uplink_release_ind *r = &ran_dec_msg.uplink_release_ind; + + const struct tlv_p_entry *ie_cause = TLVP_GET(tp, GSM0808_IE_CAUSE); + const struct tlv_p_entry *ie_talker_priority = TLVP_GET(tp, GSM0808_IE_TALKER_PRIORITY); + + /* Cause, 3.2.2.5 */ + if (!ie_cause || ie_cause->len < 1) { + LOG_RAN_A_DEC_MSG(LOGL_ERROR, "Mandatory IE missing: Cause\n"); + return -EINVAL; + } + r->cause = ie_cause->val[0]; + + /* Talker Priority, 3.2.2.89 */ + if (ie_talker_priority) { + r->talker_priority = ie_talker_priority->val[0] & 0x03; + r->talker_priority_present = true; + } + + return ran_decoded(ran_dec, &ran_dec_msg); +} + +static int ran_a_decode_vgcs_vbs_assign_status(struct ran_dec *ran_dec, const struct msgb *msg, + const struct tlv_parsed *tp) +{ + struct ran_msg ran_dec_msg = { + .msg_type = RAN_MSG_VGCS_VBS_ASSIGN_STATUS, + .msg_name = "BSSMAP VGCS/VBS ASSIGNMENT STATUS", + }; + struct gsm0808_vgcs_vbs_assign_stat *r = &ran_dec_msg.vgcs_vbs_assign_stat; + int rc; + + const struct tlv_p_entry *ie_cils_est = TLVP_GET(tp, GSM0808_IE_CELL_ID_LIST_SEG_EST_CELLS); + const struct tlv_p_entry *ie_cils_tbe = TLVP_GET(tp, GSM0808_IE_CELL_ID_LIST_SEG_CELLS_TBE); + const struct tlv_p_entry *ie_cils_rel = TLVP_GET(tp, GSM0808_IE_CELL_ID_LIST_SEG_REL_CELLS); + const struct tlv_p_entry *ie_cils_ne = TLVP_GET(tp, GSM0808_IE_CELL_ID_LIST_SEG_NE_CELLS); + const struct tlv_p_entry *ie_cell_status = TLVP_GET(tp, GSM0808_IE_VGCS_VBS_CELL_STATUS); + + /* Cell Identifier List Segment, 3.2.2.27b */ + if (ie_cils_est) { + rc = gsm0808_dec_cell_id_list_segment(&r->cils_est, ie_cils_est->val, ie_cils_est->len); + if (rc < 0) { + LOG_RAN_A_DEC_MSG(LOGL_ERROR, "Decoding Cell Identifier gave rc=%d\n", rc); + return -EINVAL; + } + r->cils_est_present = true; + } + + /* Cell Identifier List Segment, 3.2.2.27c */ + if (ie_cils_tbe) { + rc = gsm0808_dec_cell_id_list_segment(&r->cils_tbe, ie_cils_tbe->val, ie_cils_tbe->len); + if (rc < 0) { + LOG_RAN_A_DEC_MSG(LOGL_ERROR, "Decoding Cell Identifier gave rc=%d\n", rc); + return -EINVAL; + } + r->cils_tbe_present = true; + } + + /* Cell Identifier List Segment, 3.2.2.27e */ + if (ie_cils_rel) { + rc = gsm0808_dec_cell_id_list_segment(&r->cils_rel, ie_cils_rel->val, ie_cils_rel->len); + if (rc < 0) { + LOG_RAN_A_DEC_MSG(LOGL_ERROR, "Decoding Cell Identifier gave rc=%d\n", rc); + return -EINVAL; + } + r->cils_rel_present = true; + } + + /* Cell Identifier List Segment, 3.2.2.27f */ + if (ie_cils_ne) { + rc = gsm0808_dec_cell_id_list_segment(&r->cils_ne, ie_cils_ne->val, ie_cils_ne->len); + if (rc < 0) { + LOG_RAN_A_DEC_MSG(LOGL_ERROR, "Decoding Cell Identifier gave rc=%d\n", rc); + return -EINVAL; + } + r->cils_ne_present = true; + } + + /* VGCS/VBS Cell Status, 3.2.2.94 */ + if (ie_cell_status && ie_cell_status->len) { + r->cell_status = ie_cell_status->val[0] & 0x73; + r->cell_status_present = true; + } + + return ran_decoded(ran_dec, &ran_dec_msg); +} + static int ran_a_decode_bssmap(struct ran_dec *ran_dec, struct msgb *bssmap) { struct tlv_parsed tp[2]; @@ -813,6 +1245,26 @@ static int ran_a_decode_bssmap(struct ran_dec *ran_dec, struct msgb *bssmap) return ran_a_decode_sapi_n_reject(ran_dec, bssmap, tp); case BSS_MAP_MSG_LCLS_NOTIFICATION: return ran_a_decode_lcls_notification(ran_dec, bssmap, tp); + case BSS_MAP_MSG_VGCS_VBS_SETUP_ACK: + return ran_a_decode_vgcs_vbs_setup_ack(ran_dec, bssmap, tp); + case BSS_MAP_MSG_VGCS_VBS_SETUP_REFUSE: + return ran_a_decode_vgcs_vbs_setup_refuse(ran_dec, bssmap, tp); + case BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_RESULT: + return ran_a_decode_vgcs_vbs_assign_res(ran_dec, bssmap, tp); + case BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_FAILURE: + return ran_a_decode_vgcs_vbs_assign_fail(ran_dec, bssmap, tp); + case BSS_MAP_MSG_VGCS_VBS_QUEUING_INDICATION: + return ran_a_decode_vgcs_vbs_queuing_ind(ran_dec, bssmap, tp); + case BSS_MAP_MSG_UPLINK_RQST: + return ran_a_decode_uplink_request(ran_dec, bssmap, tp); + case BSS_MAP_MSG_UPLINK_RQST_CONFIRMATION: + return ran_a_decode_uplink_request_cnf(ran_dec, bssmap, tp); + case BSS_MAP_MSG_UPLINK_APP_DATA: + return ran_a_decode_uplink_application_data(ran_dec, bssmap, tp); + case BSS_MAP_MSG_UPLINK_RELEASE_INDICATION: + return ran_a_decode_uplink_release_ind(ran_dec, bssmap, tp); + case BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_STATUS: + return ran_a_decode_vgcs_vbs_assign_status(ran_dec, bssmap, tp); /* From current RAN peer, the Handover origin: */ case BSS_MAP_MSG_HANDOVER_REQUIRED: @@ -1293,6 +1745,36 @@ static struct msgb *_ran_a_encode(struct osmo_fsm_inst *caller_fi, const struct case RAN_MSG_HANDOVER_FAILURE: return ran_a_make_handover_failure(caller_fi, ran_enc_msg); + case RAN_MSG_VGCS_VBS_SETUP: + return gsm0808_create_vgcs_vbs_setup(&ran_enc_msg->vgcs_vbs_setup); + + case RAN_MSG_VGCS_VBS_ASSIGN_REQ: + return gsm0808_create_vgcs_vbs_assign_req(&ran_enc_msg->vgcs_vbs_assign_req); + + case RAN_MSG_UPLINK_REQUEST_ACK: + return gsm0808_create_uplink_request_ack(&ran_enc_msg->uplink_request_ack); + + case RAN_MSG_UPLINK_REJECT_CMD: + return gsm0808_create_uplink_reject_cmd(&ran_enc_msg->uplink_reject_cmd); + + case RAN_MSG_UPLINK_RELEASE_CMD: + return gsm0808_create_uplink_release_cmd(ran_enc_msg->uplink_release_cmd.cause); + + case RAN_MSG_UPLINK_SEIZED_CMD: + return gsm0808_create_uplink_seized_cmd(&ran_enc_msg->uplink_seized_cmd); + + case RAN_MSG_VGCS_ADDITIONAL_INFO: + return gsm0808_create_vgcs_additional_info(&ran_enc_msg->vgcs_additional_info.talker_identity); + + case RAN_MSG_VGCS_VBS_AREA_CELL_INFO: + return gsm0808_create_vgcs_vbs_area_cell_info(&ran_enc_msg->vgcs_vbs_area_cell_info); + + case RAN_MSG_VGCS_SMS: + return gsm0808_create_vgcs_sms(&ran_enc_msg->vgcs_sms.sms_to_vgcs); + + case RAN_MSG_NOTIFICATION_DATA: + return gsm0808_create_notification_data(&ran_enc_msg->notification_data); + default: LOG_RAN_A_ENC(caller_fi, LOGL_ERROR, "Unimplemented RAN-encode message type: %s\n", ran_msg_type_name(ran_enc_msg->msg_type)); |