diff options
Diffstat (limited to 'src/gsm/gsm0808.c')
-rw-r--r-- | src/gsm/gsm0808.c | 984 |
1 files changed, 924 insertions, 60 deletions
diff --git a/src/gsm/gsm0808.c b/src/gsm/gsm0808.c index 971d9625..529dbdfe 100644 --- a/src/gsm/gsm0808.c +++ b/src/gsm/gsm0808.c @@ -15,12 +15,10 @@ * 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 "config.h" + #include <string.h> #include <osmocom/core/byteswap.h> @@ -104,13 +102,19 @@ struct msgb *gsm0808_create_layer3_2(const struct msgb *msg_l3, const struct osm msgb_l3len(msg_l3), msg_l3->l3h); /* AoIP: add Codec List (BSS Supported) 3.2.2.103 */ - if (scl) - gsm0808_enc_speech_codec_list(msg, scl); + if (scl) { + if (gsm0808_enc_speech_codec_list2(msg, scl) < 0) + goto exit_free; + } /* push the bssmap header */ msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); return msg; + +exit_free: + msgb_free(msg); + return NULL; } /*! Create "Complete L3 Info" for A, legacy implementation. @@ -228,22 +232,32 @@ struct msgb *gsm0808_create_clear_command2(uint8_t cause, bool csfb_ind) return msg; } -/*! Create BSSMAP Cipher Mode Command message +/*! Superseded by gsm0808_create_cipher2() to include Kc128. + * Create BSSMAP Cipher Mode Command message (without Kc128). * \param[in] ei Mandatory Encryption Information + * \param[in] kc128 optional kc128 key for A5/4 * \param[in] cipher_response_mode optional 1-byte Cipher Response Mode * \returns callee-allocated msgb with BSSMAP Cipher Mode Command message */ struct msgb *gsm0808_create_cipher(const struct gsm0808_encrypt_info *ei, const uint8_t *cipher_response_mode) { + struct gsm0808_cipher_mode_command cmc = { + .ei = *ei, + .cipher_response_mode_present = (cipher_response_mode != NULL), + .cipher_response_mode = (cipher_response_mode ? *cipher_response_mode : 0), + }; + return gsm0808_create_cipher2(&cmc); +} + +/*! Create BSSMAP Cipher Mode Command message. + * \param[in] cmc Information to encode. + * \returns callee-allocated msgb with BSSMAP Cipher Mode Command message */ +struct msgb *gsm0808_create_cipher2(const struct gsm0808_cipher_mode_command *cmc) +{ /* See also: 3GPP TS 48.008 3.2.1.30 CIPHER MODE COMMAND */ struct msgb *msg; - /* Mandatory emelent! */ - OSMO_ASSERT(ei); - - msg = - msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, - "cipher-mode-command"); + msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, "cipher-mode-command"); if (!msg) return NULL; @@ -251,12 +265,16 @@ struct msgb *gsm0808_create_cipher(const struct gsm0808_encrypt_info *ei, msgb_v_put(msg, BSS_MAP_MSG_CIPHER_MODE_CMD); /* Encryption Information 3.2.2.10 */ - gsm0808_enc_encrypt_info(msg, ei); + gsm0808_enc_encrypt_info(msg, &cmc->ei); /* Cipher Response Mode 3.2.2.34 */ - if (cipher_response_mode) + if (cmc->cipher_response_mode_present) msgb_tv_put(msg, GSM0808_IE_CIPHER_RESPONSE_MODE, - *cipher_response_mode); + cmc->cipher_response_mode); + + /* Kc128 3.2.2.109 */ + if (cmc->kc128_present) + gsm0808_enc_kc128(msg, cmc->kc128); /* pre-pend the header */ msg->l3h = @@ -363,7 +381,7 @@ struct msgb *gsm0808_create_lcls_conn_ctrl(enum gsm0808_lcls_config config, if (config != GSM0808_LCLS_CFG_NA) msgb_tv_put(msg, GSM0808_IE_LCLS_CONFIG, config); if (control != GSM0808_LCLS_CSC_NA) - msgb_tv_put(msg, GSM0808_IE_LCLS_CONFIG, control); + msgb_tv_put(msg, GSM0808_IE_LCLS_CONN_STATUS_CTRL, control); msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); return msg; @@ -408,7 +426,7 @@ struct msgb *gsm0808_create_lcls_notification(enum gsm0808_lcls_status status, b /*! Create BSSMAP Classmark Request message * \returns callee-allocated msgb with BSSMAP Classmark Request message */ -struct msgb *gsm0808_create_classmark_request() +struct msgb *gsm0808_create_classmark_request(void) { struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, "classmark-request"); @@ -494,8 +512,6 @@ struct msgb *gsm0808_create_ass2(const struct gsm0808_channel_type *ct, { /* See also: 3GPP TS 48.008 3.2.1.1 ASSIGNMENT REQUEST */ struct msgb *msg; - uint16_t cic_sw; - uint32_t ci_sw; /* Mandatory emelent! */ OSMO_ASSERT(ct); @@ -513,11 +529,8 @@ struct msgb *gsm0808_create_ass2(const struct gsm0808_channel_type *ct, gsm0808_enc_channel_type(msg, ct); /* Circuit Identity Code 3.2.2.2 */ - if (cic) { - cic_sw = osmo_htons(*cic); - msgb_tv_fixed_put(msg, GSM0808_IE_CIRCUIT_IDENTITY_CODE, - sizeof(cic_sw), (uint8_t *) & cic_sw); - } + if (cic) + msgb_tv16_put(msg, GSM0808_IE_CIRCUIT_IDENTITY_CODE, *cic); /* AoIP: AoIP Transport Layer Address (MGW) 3.2.2.102 */ if (ss) { @@ -525,23 +538,17 @@ struct msgb *gsm0808_create_ass2(const struct gsm0808_channel_type *ct, } /* AoIP: Codec List (MSC Preferred) 3.2.2.103 */ - if (scl) - gsm0808_enc_speech_codec_list(msg, scl); + if (scl) { + if (gsm0808_enc_speech_codec_list2(msg, scl) < 0) + goto exit_free; + } /* AoIP: Call Identifier 3.2.2.105 */ if (ci) { /* NOTE: 3GPP TS 48.008, section 3.2.2.105 specifies that - the least significant byte should be transmitted first. - On x86, this would mean that the endieness is already - correct, however a platform independed implementation - is required: */ -#ifndef OSMO_IS_LITTLE_ENDIAN - ci_sw = osmo_swab32(*ci); -#else - ci_sw = *ci; -#endif - msgb_tv_fixed_put(msg, GSM0808_IE_CALL_ID, sizeof(ci_sw), - (uint8_t *) & ci_sw); + * the least significant byte shall be transmitted first. */ + msgb_v_put(msg, GSM0808_IE_CALL_ID); + osmo_store32le(*ci, msgb_put(msg, sizeof(*ci))); } if (kc) @@ -555,6 +562,10 @@ struct msgb *gsm0808_create_ass2(const struct gsm0808_channel_type *ct, msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); return msg; + +exit_free: + msgb_free(msg); + return NULL; } /*! Create BSSMAP Assignment Request message, 3GPP TS 48.008 §3.2.1.1. @@ -619,12 +630,16 @@ struct msgb *gsm0808_create_ass_compl2(uint8_t rr_cause, uint8_t chosen_channel, gsm0808_enc_aoip_trasp_addr(msg, ss); /* AoIP: Speech Codec (Chosen) 3.2.2.104 */ - if (sc) - gsm0808_enc_speech_codec(msg, sc); + if (sc) { + if (gsm0808_enc_speech_codec2(msg, sc) < 0) + goto exit_free; + } /* AoIP: add Codec List (BSS Supported) 3.2.2.103 */ - if (scl) - gsm0808_enc_speech_codec_list(msg, scl); + if (scl) { + if (gsm0808_enc_speech_codec_list2(msg, scl) < 0) + goto exit_free; + } /* FIXME: write LSA identifier 3.2.2.15 - see 3GPP TS 43.073 */ @@ -635,6 +650,10 @@ struct msgb *gsm0808_create_ass_compl2(uint8_t rr_cause, uint8_t chosen_channel, msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); return msg; + +exit_free: + msgb_free(msg); + return NULL; } /*! Create BSSMAP Assignment Completed message @@ -696,13 +715,19 @@ struct msgb *gsm0808_create_ass_fail(uint8_t cause, const uint8_t *rr_cause, /* Circuit pool list 3.2.2.46 */ /* AoIP: add Codec List (BSS Supported) 3.2.2.103 */ - if (scl) - gsm0808_enc_speech_codec_list(msg, scl); + if (scl) { + if (gsm0808_enc_speech_codec_list2(msg, scl) < 0) + goto exit_free; + } /* update the size */ msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); return msg; + +exit_free: + msgb_free(msg); + return NULL; } /*! Create BSSMAP Assignment Failure message @@ -804,7 +829,7 @@ struct msgb *gsm0808_create_paging(const char *imsi, const uint32_t *tmsi, { struct gsm0808_cell_id_list2 cil2 = {}; - /* Mandatory emelents! */ + /* Mandatory elements! */ OSMO_ASSERT(cil); if (cil->id_list_len > GSM0808_CELL_ID_LIST2_MAXLEN) @@ -846,6 +871,11 @@ static uint8_t put_old_bss_to_new_bss_information(struct msgb *msg, msgb_tlv_put(msg, GSM0808_FE_IE_CURRENT_CHANNEL_TYPE_2, 2, val); } + if (i->last_eutran_plmn_id_present) { + msgb_put_u8(msg, GSM0808_FE_IE_LAST_USED_EUTRAN_PLMN_ID); + osmo_plmn_to_bcd(msgb_put(msg, 3), &i->last_eutran_plmn_id); + } + *tlv_len = (uint8_t) (msg->tail - old_tail); return *tlv_len + 2; } @@ -990,8 +1020,10 @@ struct msgb *gsm0808_create_handover_request(const struct gsm0808_handover_reque if (params->aoip_transport_layer) gsm0808_enc_aoip_trasp_addr(msg, params->aoip_transport_layer); - if (params->codec_list_msc_preferred) - gsm0808_enc_speech_codec_list(msg, params->codec_list_msc_preferred); + if (params->codec_list_msc_preferred) { + if (gsm0808_enc_speech_codec_list2(msg, params->codec_list_msc_preferred) < 0) + goto exit_free; + } if (params->call_id_present) { uint8_t val[4]; @@ -999,6 +1031,9 @@ struct msgb *gsm0808_create_handover_request(const struct gsm0808_handover_reque msgb_tv_fixed_put(msg, GSM0808_IE_CALL_ID, 4, val); } + if (params->more_items && params->kc128_present) + gsm0808_enc_kc128(msg, params->kc128); + if (params->global_call_reference && params->global_call_reference_len) { msgb_tlv_put(msg, GSM0808_IE_GLOBAL_CALL_REF, params->global_call_reference_len, params->global_call_reference); @@ -1008,6 +1043,10 @@ struct msgb *gsm0808_create_handover_request(const struct gsm0808_handover_reque msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); return msg; + +exit_free: + msgb_free(msg); + return NULL; } /*! Create BSSMAP HANDOVER REQUEST ACKNOWLEDGE message, 3GPP TS 48.008 3.2.1.10. @@ -1040,14 +1079,28 @@ struct msgb *gsm0808_create_handover_request_ack2(const struct gsm0808_handover_ if (params->aoip_transport_layer) gsm0808_enc_aoip_trasp_addr(msg, params->aoip_transport_layer); + /* AoIP: add Codec List (BSS Supported) 3.2.2.103. + * (codec_list_bss_supported was added to struct gsm0808_handover_request_ack later than speech_codec_chosen + * below, but it needs to come before it in the message coding). */ + if (params->more_items && params->codec_list_bss_supported.len) { + if (gsm0808_enc_speech_codec_list2(msg, ¶ms->codec_list_bss_supported) < 0) + goto exit_free; + } + /* AoIP: Speech Codec (Chosen) 3.2.2.104 */ - if (params->speech_codec_chosen_present) - gsm0808_enc_speech_codec(msg, ¶ms->speech_codec_chosen); + if (params->speech_codec_chosen_present) { + if (gsm0808_enc_speech_codec2(msg, ¶ms->speech_codec_chosen) < 0) + goto exit_free; + } /* prepend header with final length */ msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); return msg; + +exit_free: + msgb_free(msg); + return NULL; } /*! Same as gsm0808_create_handover_request_ack2() but with less parameters. @@ -1099,7 +1152,7 @@ struct msgb *gsm0808_create_handover_command(const struct gsm0808_handover_comma /*! Create BSSMAP HANDOVER DETECT message, 3GPP TS 48.008 3.2.1.40. * Sent from the MT BSC back to the MSC when the MS has sent a handover RACH request and the MT BSC has * received the Handover Detect message. */ -struct msgb *gsm0808_create_handover_detect() +struct msgb *gsm0808_create_handover_detect(void) { struct msgb *msg; @@ -1118,7 +1171,7 @@ struct msgb *gsm0808_create_handover_detect() /*! Create BSSMAP HANDOVER SUCCEEDED message, 3GPP TS 48.008 3.2.1.13. * Sent from the MSC back to the old BSS to notify that the MS has successfully accessed the new BSS. */ -struct msgb *gsm0808_create_handover_succeeded() +struct msgb *gsm0808_create_handover_succeeded(void) { struct msgb *msg; @@ -1153,12 +1206,16 @@ struct msgb *gsm0808_create_handover_complete(const struct gsm0808_handover_comp msgb_tlv_put(msg, GSM0808_IE_RR_CAUSE, 1, ¶ms->rr_cause); /* AoIP: Speech Codec (Chosen) 3.2.2.104 */ - if (params->speech_codec_chosen_present) - gsm0808_enc_speech_codec(msg, ¶ms->speech_codec_chosen); + if (params->speech_codec_chosen_present) { + if (gsm0808_enc_speech_codec2(msg, ¶ms->speech_codec_chosen) < 0) + goto exit_free; + } /* AoIP: add Codec List (BSS Supported) 3.2.2.103 */ - if (params->codec_list_bss_supported.len) - gsm0808_enc_speech_codec_list(msg, ¶ms->codec_list_bss_supported); + if (params->codec_list_bss_supported.len) { + if (gsm0808_enc_speech_codec_list2(msg, ¶ms->codec_list_bss_supported) < 0) + goto exit_free; + } /* Chosen Encryption Algorithm 3.2.2.44 */ if (params->chosen_encr_alg_present && params->chosen_encr_alg > 0) @@ -1172,6 +1229,10 @@ struct msgb *gsm0808_create_handover_complete(const struct gsm0808_handover_comp msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); return msg; + +exit_free: + msgb_free(msg); + return NULL; } /*! Create BSSMAP HANDOVER FAILURE message, 3GPP TS 48.008 3.2.1.16. @@ -1195,13 +1256,19 @@ struct msgb *gsm0808_create_handover_failure(const struct gsm0808_handover_failu msgb_tlv_put(msg, GSM0808_IE_RR_CAUSE, 1, ¶ms->rr_cause); /* AoIP: add Codec List (BSS Supported) 3.2.2.103 */ - if (params->codec_list_bss_supported.len) - gsm0808_enc_speech_codec_list(msg, ¶ms->codec_list_bss_supported); + if (params->codec_list_bss_supported.len) { + if (gsm0808_enc_speech_codec_list2(msg, ¶ms->codec_list_bss_supported) < 0) + goto exit_free; + } /* prepend header with final length */ msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); return msg; + +exit_free: + msgb_free(msg); + return NULL; } /*! Create BSSMAP HANDOVER PERFORMED message, 3GPP TS 48.008 3.2.1.25. @@ -1237,8 +1304,10 @@ struct msgb *gsm0808_create_handover_performed(const struct gsm0808_handover_per msgb_tv_put(msg, GSM0808_IE_SPEECH_VERSION, params->speech_version_chosen); /* AoIP: Speech Codec (chosen) 3.2.2.104 */ - if (params->speech_codec_chosen_present) - gsm0808_enc_speech_codec(msg, ¶ms->speech_codec_chosen); + if (params->speech_codec_chosen_present) { + if (gsm0808_enc_speech_codec2(msg, ¶ms->speech_codec_chosen) < 0) + goto exit_free; + } /* LCLS-BSS-Status 3.2.2.119 */ if (params->lcls_bss_status_present) @@ -1248,6 +1317,10 @@ struct msgb *gsm0808_create_handover_performed(const struct gsm0808_handover_per msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); return msg; + +exit_free: + msgb_free(msg); + return NULL; } /*! Create BSSMAP COMMON ID message, 3GPP TS 48.008 3.2.1.68. @@ -1443,6 +1516,663 @@ struct msgb *gsm0808_create_perform_location_abort(const struct lcs_cause_ie *lc return msg; } +/*! Create BSSMAP VGCS/VBS SETUP message, 3GPP TS 48.008 3.2.1.50. + * Sent from the MSC to the BSC to request VGCS/VBS call. */ +struct msgb *gsm0808_create_vgcs_vbs_setup(const struct gsm0808_vgcs_vbs_setup *params) +{ + struct msgb *msg; + + msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, "BSSMAP-VGCS/VBS-SETUP"); + if (!msg) + return NULL; + + /* Message Type, 3.2.2.1 */ + msgb_v_put(msg, BSS_MAP_MSG_VGCS_VBS_SETUP); + + /* Group Call Reference, 3.2.2.55 */ + gsm0808_enc_group_callref(msg, ¶ms->callref); + + /* Priority, 3.2.2.18 */ + if (params->priority_present) + gsm0808_enc_priority(msg, ¶ms->priority); + + /* VGCS Feature Flags, 3.2.2.88 */ + if (params->vgcs_feature_flags_present) + gsm0808_enc_vgcs_feature_flags(msg, ¶ms->flags); + + /* prepend header with final length */ + msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); + + return msg; +} + +/*! Create BSSMAP VGCS/VBS SETUP ACK message, 3GPP TS 48.008 3.2.1.51. + * Sent from the BSC to the MSC to confirm VGCS/VBS call. */ +struct msgb *gsm0808_create_vgcs_vbs_setup_ack(const struct gsm0808_vgcs_vbs_setup_ack *params) +{ + struct msgb *msg; + + msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, "BSSMAP-VGCS/VBS-SETUP-ACK"); + if (!msg) + return NULL; + + /* Message Type, 3.2.2.1 */ + msgb_v_put(msg, BSS_MAP_MSG_VGCS_VBS_SETUP_ACK); + + /* VGCS Feature Flags, 3.2.2.88 */ + if (params->vgcs_feature_flags_present) + gsm0808_enc_vgcs_feature_flags(msg, ¶ms->flags); + + /* prepend header with final length */ + msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); + + return msg; +} + +/*! Create BSSMAP VGCS/VBS SETUP REFUSE message, 3GPP TS 48.008 3.2.1.52. + * Sent from the BSC to the MSC to reject VGCS/VBS call. */ +struct msgb *gsm0808_create_vgcs_vbs_setup_refuse(enum gsm0808_cause cause) +{ + struct msgb *msg; + + msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, "BSSMAP-VGCS/VBS-SETUP-REFUSE"); + if (!msg) + return NULL; + + /* Message Type, 3.2.2.1 */ + msgb_v_put(msg, BSS_MAP_MSG_VGCS_VBS_SETUP_REFUSE); + + /* Cause, 3.2.2.5 */ + gsm0808_enc_cause(msg, cause); + + /* prepend header with final length */ + msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); + + return msg; +} + +/*! Create BSSMAP VGCS/VBS ASSIGNMENT REQUEST message, 3GPP TS 48.008 3.2.1.53. + * Sent from the MSC to the BSC to assign radio resources for a VGCS/VBS. */ +struct msgb *gsm0808_create_vgcs_vbs_assign_req(const struct gsm0808_vgcs_vbs_assign_req *params) +{ + struct msgb *msg; + + msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, "BSSMAP-VGCS/VBS-ASSIGNMENT-REQUEST"); + if (!msg) + return NULL; + + /* Message Type, 3.2.2.1 */ + msgb_v_put(msg, BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_RQST); + + /* Channel Type, 3.2.2.11 */ + gsm0808_enc_channel_type(msg, ¶ms->channel_type); + + /* Assignment Requrirement, 3.2.2.52 */ + gsm0808_enc_assign_req(msg, params->ass_req); + + /* Cell Identifier, 3.2.2.17 */ + gsm0808_enc_cell_id(msg, ¶ms->cell_identifier); + + /* Group Call Reference, 3.2.2.55 */ + gsm0808_enc_group_callref(msg, ¶ms->callref); + + /* Priority, 3.2.2.18 */ + if (params->priority_present) + gsm0808_enc_priority(msg, ¶ms->priority); + + /* Circuit Identity Code, 3.2.2.2 */ + if (params->cic_present) + msgb_tv16_put(msg, GSM0808_IE_CIRCUIT_IDENTITY_CODE, params->cic); + + /* Downlink DTX Flag, 3.2.2.26 */ + if (params->downlink_dtx_flag_present) + msgb_tv_put(msg, GSM0808_IE_DOWNLINK_DTX_FLAG, params->downlink_dtx_flag); + + /* Encryption Information, 3.2.2.10 */ + if (params->encryption_information_present) + gsm0808_enc_encrypt_info(msg, ¶ms->encryption_information); + + /* VSTK_RAND Imformation, 3.2.2.83 */ + if (params->vstk_rand_present) + msgb_tlv_put(msg, GSM0808_IE_VSTK_RAND_INFO, sizeof(params->vstk_rand), params->vstk_rand); + + /* VSTK Information, 3.2.2.84 */ + if (params->vstk_present) + msgb_tlv_put(msg, GSM0808_IE_VSTK_INFO, sizeof(params->vstk), params->vstk); + + /* Cell Identifier List Segment, 3.2.2.27a */ + if (params->cils_present) + gsm0808_enc_cell_id_list_segment(msg, GSM0808_IE_CELL_ID_LIST_SEGMENT, ¶ms->cils); + + /* AoIP Transport Layer Address (MGW), 3.2.2.102 */ + if (params->aoip_transport_layer_present) + gsm0808_enc_aoip_trasp_addr(msg, ¶ms->aoip_transport_layer); + + /* Call Identifier, 3.2.2.105 */ + if (params->call_id_present) { + /* NOTE: 3GPP TS 48.008, section 3.2.2.105 specifies that + * the least significant byte shall be transmitted first. */ + msgb_v_put(msg, GSM0808_IE_CALL_ID); + osmo_store32le(params->call_id, msgb_put(msg, sizeof(uint32_t))); + } + + /* Codec List (MSC Preferred) 3.2.2.103 */ + if (params->codec_list_present) { + if (gsm0808_enc_speech_codec_list2(msg, ¶ms->codec_list_msc_preferred) < 0) + goto exit_free; + } + + /* prepend header with final length */ + msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); + + return msg; + +exit_free: + msgb_free(msg); + return NULL; +} + +/*! Create BSSMAP VGCS/VBS ASSIGNMENT RESULT message, 3GPP TS 48.008 3.2.1.54. + * Sent from the BSC to the MSC to indicate assignment/deassingment of radio resources for a VGCS/VBS. */ +struct msgb *gsm0808_create_vgcs_vbs_assign_res(const struct gsm0808_vgcs_vbs_assign_res *params) +{ + struct msgb *msg; + + msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, "BSSMAP-VGCS/VBS-ASSIGNMENT-RESULT"); + if (!msg) + return NULL; + + /* Message Type, 3.2.2.1 */ + msgb_v_put(msg, BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_RESULT); + + /* Channel Type, 3.2.2.11 */ + gsm0808_enc_channel_type(msg, ¶ms->channel_type); + + /* Cell Identifier, 3.2.2.17 */ + gsm0808_enc_cell_id(msg, ¶ms->cell_identifier); + + /* Chosen Channel, 3.2.2.33 */ + if (params->chosen_channel_present) + msgb_tv_put(msg, GSM0808_IE_CHOSEN_CHANNEL, params->chosen_channel); + + /* Circuit Identity Code, 3.2.2.2 */ + if (params->cic_present) + msgb_tv16_put(msg, GSM0808_IE_CIRCUIT_IDENTITY_CODE, params->cic); + + /* Circuit Pool, 3.2.2.45 */ + if (params->circuit_pool_present) + msgb_tv_put(msg, GSM0808_IE_CIRCUIT_POOL, params->circuit_pool); + + /* AoIP Transport Layer Address (BSS), 3.2.2.102 */ + if (params->aoip_transport_layer_present) + gsm0808_enc_aoip_trasp_addr(msg, ¶ms->aoip_transport_layer); + + /* Codec (MSC Chosen) 3.2.2.103 */ + if (params->codec_present) { + if (gsm0808_enc_speech_codec2(msg, ¶ms->codec_msc_chosen) < 0) + goto exit_free; + } + + /* Call Identifier, 3.2.2.105 */ + if (params->call_id_present) { + /* NOTE: 3GPP TS 48.008, section 3.2.2.105 specifies that + * the least significant byte shall be transmitted first. */ + msgb_v_put(msg, GSM0808_IE_CALL_ID); + osmo_store32le(params->call_id, msgb_put(msg, sizeof(uint32_t))); + } + + /* prepend header with final length */ + msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); + + return msg; + +exit_free: + msgb_free(msg); + return NULL; +} + +/*! Create BSSMAP VGCS/VBS ASSIGNMENT FAILURE message, 3GPP TS 48.008 3.2.1.55. + * Sent from the BSC to the MSC to indicate assignment failure for a VGCS/VBS. */ +struct msgb *gsm0808_create_vgcs_vbs_assign_fail(const struct gsm0808_vgcs_vbs_assign_fail *params) +{ + struct msgb *msg; + + msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, "BSSMAP-VGCS/VBS-ASSIGNMENT-RESULT"); + if (!msg) + return NULL; + + /* Message Type, 3.2.2.1 */ + msgb_v_put(msg, BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_FAILURE); + + /* Cause, 3.2.2.5 */ + gsm0808_enc_cause(msg, params->cause); + + /* Circuit Pool, 3.2.2.45 */ + if (params->circuit_pool_present) + msgb_tv_put(msg, GSM0808_IE_CIRCUIT_POOL, params->circuit_pool); + + /* Circuit Pool List, 3.2.2.46 */ + if (params->circuit_pool_present) + msgb_tlv_put(msg, GSM0808_IE_CIRCUIT_POOL_LIST, params->cpl.list_len, params->cpl.pool); + + /* Codec List (BSS Supported) 3.2.2.103 */ + if (params->codec_list_present) { + if (gsm0808_enc_speech_codec_list2(msg, ¶ms->codec_list_bss_supported) < 0) + goto exit_free; + } + + /* prepend header with final length */ + msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); + + return msg; + +exit_free: + msgb_free(msg); + return NULL; +} + +/*! Create BSSMAP VGCS/VBS QUEUING INDICATION message, 3GPP TS 48.008 3.2.1.56. + * Sent from the BSC to the MSC to indicate delay in assignment for a VGCS/VBS. */ +struct msgb *gsm0808_create_vgcs_queuing_ind(void) +{ + struct msgb *msg; + uint8_t val = BSS_MAP_MSG_VGCS_VBS_QUEUING_INDICATION; + + msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, "BSSMAP-VGCS/VBS-QUEUING-INDICATION"); + if (!msg) + return NULL; + + msg->l3h = msg->data; + msgb_tlv_put(msg, BSSAP_MSG_BSS_MANAGEMENT, 1, &val); + + return msg; +} + +/*! Create BSSMAP (VGCS) UPLINK REQUEST message, 3GPP TS 48.008 3.2.1.57. + * Sent from the BSC to the MSC to indicate that a mobile requested access to uplink. */ +struct msgb *gsm0808_create_uplink_request(const struct gsm0808_uplink_request *params) +{ + struct msgb *msg; + int rc; + + msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, "BSSMAP-UPLINK-REQUEST"); + if (!msg) + return NULL; + + /* Message Type, 3.2.2.1 */ + msgb_v_put(msg, BSS_MAP_MSG_UPLINK_RQST); + + /* Talker Priority, 3.2.2.89 */ + if (params->talker_priority_present) + msgb_tv_put(msg, GSM0808_IE_TALKER_PRIORITY, params->talker_priority); + + /* Cell Identifier, 3.2.2.17 */ + if (params->cell_identifier_present) + gsm0808_enc_cell_id(msg, ¶ms->cell_identifier); + + /* Layer 3 Information, 3.2.2.24 */ + if (params->l3_present) + msgb_tlv_put(msg, GSM0808_IE_LAYER_3_INFORMATION, params->l3.l3_len, params->l3.l3); + + /* Mobile Identity, 3.2.2.41 */ + if (params->mi_present) { + rc = osmo_mobile_identity_encode_msgb(msg, ¶ms->mi, false); + if (rc < 0) { + msgb_free(msg); + return NULL; + } + } + + /* prepend header with final length */ + msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); + + return msg; +} + +/*! Create BSSMAP (VGCS) UPLINK REQUEST ACKNOWLEDGE message, 3GPP TS 48.008 3.2.1.58. + * Sent from the MSC to the BSC to indicate that access to uplink was granted. */ +struct msgb *gsm0808_create_uplink_request_ack(const struct gsm0808_uplink_request_ack *params) +{ + struct msgb *msg; + + msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, "BSSMAP-UPLINK-REQUEST-ACKNOWLEDGE"); + if (!msg) + return NULL; + + /* Message Type, 3.2.2.1 */ + msgb_v_put(msg, BSS_MAP_MSG_UPLINK_RQST_ACKNOWLEDGE); + + /* Talker Priority, 3.2.2.89 */ + if (params->talker_priority_present) + msgb_tv_put(msg, GSM0808_IE_TALKER_PRIORITY, params->talker_priority); + + /* Emergency set indication, 3.2.2.90 */ + if (params->emerg_set_ind_present) + msgb_v_put(msg, GSM0808_IE_EMERGENCY_SET_INDICATION); + + /* Talker Identity, 3.2.2.91 */ + if (params->talker_identity_present) + gsm0808_enc_talker_identity(msg, ¶ms->talker_identity); + + /* prepend header with final length */ + msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); + + return msg; +} + +/*! Create BSSMAP (VGCS) UPLINK CONFIRM message, 3GPP TS 48.008 3.2.1.59. + * Sent from the BSC to the MSC to indicate that access to uplink was has been successfully established. */ +struct msgb *gsm0808_create_uplink_request_cnf(const struct gsm0808_uplink_request_cnf *params) +{ + struct msgb *msg; + + msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, "BSSMAP-UPLINK-REQUEST-CONFIRM"); + if (!msg) + return NULL; + + /* Message Type, 3.2.2.1 */ + msgb_v_put(msg, BSS_MAP_MSG_UPLINK_RQST_CONFIRMATION); + + /* Cell Identifier, 3.2.2.17 */ + gsm0808_enc_cell_id(msg, ¶ms->cell_identifier); + + /* Talker Identity, 3.2.2.91 */ + if (params->talker_identity_present) + gsm0808_enc_talker_identity(msg, ¶ms->talker_identity); + + /* Layer 3 Information, 3.2.2.24 */ + msgb_tlv_put(msg, GSM0808_IE_LAYER_3_INFORMATION, params->l3.l3_len, params->l3.l3); + + /* prepend header with final length */ + msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); + + return msg; +} + +/*! Create BSSMAP (VGCS) UPLINK APPLICATION DATA message, 3GPP TS 48.008 3.2.1.59a. + * Sent from the BSC to the MSC to pass L3 info from the talker. */ +struct msgb *gsm0808_create_uplink_app_data(const struct gsm0808_uplink_app_data *params) +{ + struct msgb *msg; + uint8_t val; + + msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, "BSSMAP-UPLINK-APPLICATION-DATA"); + if (!msg) + return NULL; + + /* Message Type, 3.2.2.1 */ + msgb_v_put(msg, BSS_MAP_MSG_UPLINK_APP_DATA); + + /* Cell Identifier, 3.2.2.17 */ + gsm0808_enc_cell_id(msg, ¶ms->cell_identifier); + + /* Layer 3 Information, 3.2.2.24 */ + msgb_tlv_put(msg, GSM0808_IE_LAYER_3_INFORMATION, params->l3.l3_len, params->l3.l3); + + /* Application Data Information, 3.2.2.100 */ + val = params->bt_ind; + msgb_tlv_put(msg, GSM0808_IE_APP_DATA_INFO, 1, &val); + + /* prepend header with final length */ + msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); + + return msg; +} + +/*! Create BSSMAP (VGCS) UPLINK RELEASE INDICATION message, 3GPP TS 48.008 3.2.1.60. + * Sent from the BSC to the MSC to indicate that the uplink has been released. */ +struct msgb *gsm0808_create_uplink_release_ind(const struct gsm0808_uplink_release_ind *params) +{ + struct msgb *msg; + + msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, "BSSMAP-UPLINK-RELEASE-INDICATION"); + if (!msg) + return NULL; + + /* Message Type, 3.2.2.1 */ + msgb_v_put(msg, BSS_MAP_MSG_UPLINK_RELEASE_INDICATION); + + /* Cause, 3.2.2.5 */ + gsm0808_enc_cause(msg, params->cause); + + /* Talker Priority, 3.2.2.89 */ + if (params->talker_priority_present) + msgb_tv_put(msg, GSM0808_IE_TALKER_PRIORITY, params->talker_priority); + + /* prepend header with final length */ + msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); + + return msg; +} + +/*! Create BSSMAP (VGCS) UPLINK REJECT COMMAND message, 3GPP TS 48.008 3.2.1.61. + * Sent from the MSC to the BSC to indicate that the uplink is not available for allocation. */ +struct msgb *gsm0808_create_uplink_reject_cmd(const struct gsm0808_uplink_reject_cmd *params) +{ + struct msgb *msg; + + msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, "BSSMAP-UPLINK-REJECT-COMMAND"); + if (!msg) + return NULL; + + /* Message Type, 3.2.2.1 */ + msgb_v_put(msg, BSS_MAP_MSG_UPLINK_REJECT_CMD); + + /* Cause, 3.2.2.5 */ + gsm0808_enc_cause(msg, params->cause); + + /* Talker Priority, 3.2.2.89 */ + if (params->current_talker_priority_present) + msgb_tv_put(msg, GSM0808_IE_TALKER_PRIORITY, params->current_talker_priority); + + /* Talker Priority, 3.2.2.89 */ + if (params->rejected_talker_priority_present) + msgb_tv_put(msg, GSM0808_IE_TALKER_PRIORITY, params->rejected_talker_priority); + + /* Talker Identity, 3.2.2.91 */ + if (params->talker_identity_present) + gsm0808_enc_talker_identity(msg, ¶ms->talker_identity); + + /* prepend header with final length */ + msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); + + return msg; +} + +/*! Create BSSMAP (VGCS) UPLINK RELEASE COMMAND message, 3GPP TS 48.008 3.2.1.62. + * Sent from the MSC to the BSC to indicate that the uplink is available for allocation. */ +struct msgb *gsm0808_create_uplink_release_cmd(const enum gsm0808_cause cause) +{ + struct msgb *msg; + + msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, "BSSMAP-UPLINK-RELEASE-COMMAND"); + if (!msg) + return NULL; + + /* Message Type, 3.2.2.1 */ + msgb_v_put(msg, BSS_MAP_MSG_UPLINK_RELEASE_CMD); + + /* Cause, 3.2.2.5 */ + gsm0808_enc_cause(msg, cause); + + /* prepend header with final length */ + msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); + + return msg; +} + +/*! Create BSSMAP (VGCS) UPLINK SEIZED COMMAND message, 3GPP TS 48.008 3.2.1.62. + * Sent from the MSC to the BSC to indicate that the uplink is no longer available for allocation. */ +struct msgb *gsm0808_create_uplink_seized_cmd(const struct gsm0808_uplink_seized_cmd *params) +{ + struct msgb *msg; + + msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, "BSSMAP-UPLINK-SEIZED-COMMAND"); + if (!msg) + return NULL; + + /* Message Type, 3.2.2.1 */ + msgb_v_put(msg, BSS_MAP_MSG_UPLINK_SEIZED_CMD); + + /* Cause, 3.2.2.5 */ + gsm0808_enc_cause(msg, params->cause); + + /* Talker Priority, 3.2.2.89 */ + if (params->talker_priority_present) + msgb_tv_put(msg, GSM0808_IE_TALKER_PRIORITY, params->talker_priority); + + /* Emergency set indication, 3.2.2.90 */ + if (params->emerg_set_ind_present) + msgb_v_put(msg, GSM0808_IE_EMERGENCY_SET_INDICATION); + + /* Talker Identity, 3.2.2.91 */ + if (params->talker_identity_present) + gsm0808_enc_talker_identity(msg, ¶ms->talker_identity); + + /* prepend header with final length */ + msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); + + return msg; +} + +/*! Create BSSMAP VGCS ADDITIONAL INFORMATION message, 3GPP TS 48.008 3.2.1.78. + * Sent from the MSC to the BSC to transfer talker identity. */ +struct msgb *gsm0808_create_vgcs_additional_info(const struct gsm0808_talker_identity *ti) +{ + struct msgb *msg; + + msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, "BSSMAP-VGCS-ADDITIONAL-INFO"); + if (!msg) + return NULL; + + /* Message Type, 3.2.2.1 */ + msgb_v_put(msg, BSS_MAP_MSG_VGCS_ADDL_INFO); + + /* Talker Identity, 3.2.2.91 */ + gsm0808_enc_talker_identity(msg, ti); + + /* prepend header with final length */ + msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); + + return msg; +} + +/*! Create BSSMAP VGCS/VBS AREA CELL INFO message, 3GPP TS 48.008 3.2.1.79. + * Sent from the BSC to the MSC to transfer additional infos about cells. */ +struct msgb *gsm0808_create_vgcs_vbs_area_cell_info(const struct gsm0808_vgcs_vbs_area_cell_info *params) +{ + struct msgb *msg; + + msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, "BSSMAP-VGCS/VBS-AREA-CELL-INFO"); + if (!msg) + return NULL; + + /* Message Type, 3.2.2.1 */ + msgb_v_put(msg, BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_RQST); + + /* Cell Identifier List Segment, 3.2.2.27a */ + gsm0808_enc_cell_id_list_segment(msg, GSM0808_IE_CELL_ID_LIST_SEGMENT, ¶ms->cils); + + /* Assignment Requrirement, 3.2.2.52 */ + if (params->ass_req_present) + gsm0808_enc_assign_req(msg, params->ass_req); + + /* prepend header with final length */ + msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); + + return msg; +} + +/*! Create BSSMAP VGCS/VBS ASSIGNMENT STATUS message, 3GPP TS 48.008 3.2.1.80. + * Sent from the BSC to the MSC to indicate assignment status for each cell. */ +struct msgb *gsm0808_create_vgcs_vbs_assign_stat(const struct gsm0808_vgcs_vbs_assign_stat *params) +{ + struct msgb *msg; + uint8_t val; + + msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, "BSSMAP-VGCS/VBS-ASSIGNMENT-STATUS"); + if (!msg) + return NULL; + + /* Message Type, 3.2.2.1 */ + msgb_v_put(msg, BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_STATUS); + + /* Cell Identifier List Segment, 3.2.2.27b */ + if (params->cils_est_present) + gsm0808_enc_cell_id_list_segment(msg, GSM0808_IE_CELL_ID_LIST_SEG_EST_CELLS, ¶ms->cils_est); + /* Cell Identifier List Segment, 3.2.2.27c */ + if (params->cils_tbe_present) + gsm0808_enc_cell_id_list_segment(msg, GSM0808_IE_CELL_ID_LIST_SEG_CELLS_TBE, ¶ms->cils_tbe); + /* Cell Identifier List Segment, 3.2.2.27e */ + if (params->cils_rel_present) + gsm0808_enc_cell_id_list_segment(msg, GSM0808_IE_CELL_ID_LIST_SEG_REL_CELLS, ¶ms->cils_rel); + /* Cell Identifier List Segment, 3.2.2.27f */ + if (params->cils_ne_present) + gsm0808_enc_cell_id_list_segment(msg, GSM0808_IE_CELL_ID_LIST_SEG_NE_CELLS, ¶ms->cils_ne); + + /* VGCS/VBS Cell Status, 3.2.2.94 */ + if (params->cell_status_present) { + val = params->cell_status; + msgb_tlv_put(msg, GSM0808_IE_VGCS_VBS_CELL_STATUS, 1, &val); + } + + /* prepend header with final length */ + msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); + + return msg; +} + +/*! Create BSSMAP VGCS SMS message, 3GPP TS 48.008 3.2.1.81. + * Sent from the MSC to the BSC to send an SMS to VGCS. */ +struct msgb *gsm0808_create_vgcs_sms(const struct gsm0808_sms_to_vgcs *sms) +{ + struct msgb *msg; + + msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, "BSSMAP-VGCS-SMS"); + if (!msg) + return NULL; + + /* SMS to VGCS, 3.2.2.92 */ + msgb_tlv_put(msg, GSM0808_IE_VGCS_VBS_CELL_STATUS, sms->sms_len, sms->sms); + + /* prepend header with final length */ + msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); + + return msg; +} + +/*! Create BSSMAP (VGCS/VBS) NOTIFICATION DATA message, 3GPP TS 48.008 3.2.1.82. + * Sent from the MSC to the BSC to send application specific data. */ +struct msgb *gsm0808_create_notification_data(const struct gsm0808_notification_data *params) +{ + struct msgb *msg; + + msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, "BSSMAP-VGCS-SMS"); + if (!msg) + return NULL; + + /* Message Type, 3.2.2.1 */ + msgb_v_put(msg, BSS_MAP_MSG_NOTIFICATION_DATA); + + /* Application Data, 3.2.2.98 */ + msgb_tlv_put(msg, GSM0808_IE_APP_DATA, params->app_data.data_len, params->app_data.data); + + /* Data Identity, 3.2.2.99 */ + gsm0808_enc_data_identity(msg, ¶ms->data_ident); + + /* MSISDN, 3.2.2.101 */ + if (params->msisdn_present) + gsm0808_enc_msisdn(msg, params->msisdn); + + /* prepend header with final length */ + msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); + + return msg; +} + +/* Note that EMERGENCY RESET INDICATION and EMERGENCY RESET COMMAND cannot be implemented, due to lack of + * message type information in the specifications. */ + /* As per 3GPP TS 48.008 version 11.7.0 Release 11 */ static const struct tlv_definition bss_att_tlvdef = { .def = { @@ -1514,6 +2244,7 @@ static const struct tlv_definition bss_att_tlvdef = { [GSM0808_IE_LOCATION_ESTIMATE] = { TLV_TYPE_TLV }, [GSM0808_IE_POSITIONING_DATA] = { TLV_TYPE_TLV }, [GSM0808_IE_LCS_CAUSE] = { TLV_TYPE_TLV }, + [GSM0808_IE_LCS_CLIENT_TYPE] = { TLV_TYPE_TLV }, [GSM0808_IE_APDU] = { TLV_TYPE_TLV }, [GSM0808_IE_NETWORK_ELEMENT_IDENTITY] = { TLV_TYPE_TLV }, [GSM0808_IE_GPS_ASSISTANCE_DATA] = { TLV_TYPE_TLV }, @@ -1530,6 +2261,7 @@ static const struct tlv_definition bss_att_tlvdef = { [GSM0800_IE_INTER_SYSTEM_INFO] = { TLV_TYPE_TLV }, [GSM0808_IE_SNA_ACCESS_INFO] = { TLV_TYPE_TLV }, [GSM0808_IE_VSTK_RAND_INFO] = { TLV_TYPE_TLV }, + [GSM0808_IE_VSTK_INFO] = { TLV_TYPE_TLV }, [GSM0808_IE_PAGING_INFO] = { TLV_TYPE_TV }, [GSM0808_IE_IMEI] = { TLV_TYPE_TLV }, [GSM0808_IE_VELOCITY_ESTIMATE] = { TLV_TYPE_TLV }, @@ -1572,6 +2304,11 @@ static const struct tlv_definition bss_att_tlvdef = { [GSM0808_IE_CN_TO_MS_TRANSP_INFO] = { TLV_TYPE_TLV }, [GSM0808_IE_SELECTED_PLMN_ID] = { TLV_TYPE_FIXED, 3 }, [GSM0808_IE_LAST_USED_EUTRAN_PLMN_ID] = { TLV_TYPE_FIXED, 3 }, + [GSM0808_IE_OLD_LAI] = { TLV_TYPE_FIXED, 5 }, + [GSM0808_IE_ATTACH_INDICATOR] = { TLV_TYPE_T }, + [GSM0808_IE_SELECTED_OPERATOR] = { TLV_TYPE_FIXED, 3 }, + [GSM0808_IE_PS_REGISTERED_OPERATOR] = { TLV_TYPE_FIXED, 3 }, + [GSM0808_IE_CS_REGISTERED_OPERATOR] = { TLV_TYPE_FIXED, 3 }, /* Osmocom extensions */ [GSM0808_IE_OSMO_OSMUX_SUPPORT] = { TLV_TYPE_T }, @@ -1584,6 +2321,32 @@ const struct tlv_definition *gsm0808_att_tlvdef(void) return &bss_att_tlvdef; } +/* As per 3GPP TS 48.008 version 16.0.0 Release 16 § 3.2.2.58 Old BSS to New BSS Information */ +const struct tlv_definition gsm0808_old_bss_to_new_bss_info_att_tlvdef = { + .def = { + [GSM0808_FE_IE_EXTRA_INFORMATION] = { TLV_TYPE_TLV }, + [GSM0808_FE_IE_CURRENT_CHANNEL_TYPE_2] = { TLV_TYPE_TLV }, + [GSM0808_FE_IE_TARGET_CELL_RADIO_INFORMATION] = { TLV_TYPE_TLV }, + [GSM0808_FE_IE_GPRS_SUSPEND_INFORMATION] = { TLV_TYPE_TLV }, + [GSM0808_FE_IE_MULTIRATE_CONFIGURATION_INFORMATION] = { TLV_TYPE_TLV }, + [GSM0808_FE_IE_DUAL_TRANSFER_MODE_INFORMATION] = { TLV_TYPE_TLV }, + [GSM0808_FE_IE_INTER_RAT_HANDOVER_INFO] = { TLV_TYPE_TLV }, + [GSM0808_FE_IE_CDMA2000_CAPABILITY_INFORMATION] = { TLV_TYPE_TLV }, + [GSM0808_FE_IE_DOWNLINK_CELL_LOAD_INFORMATION] = { TLV_TYPE_TLV }, + [GSM0808_FE_IE_UPLINK_CELL_LOAD_INFORMATION] = { TLV_TYPE_TLV }, + [GSM0808_FE_IE_CELL_LOAD_INFORMATION_GROUP] = { TLV_TYPE_TLV }, + [GSM0808_FE_IE_CELL_LOAD_INFORMATION] = { TLV_TYPE_TLV }, + [GSM0808_FE_IE_PS_INDICATION] = { TLV_TYPE_TLV }, + [GSM0808_FE_IE_DTM_HANDOVER_COMMAND_INDICATION] = { TLV_TYPE_TLV }, + [GSM0808_FE_IE_D_RNTI] = { TLV_TYPE_TLV }, + [GSM0808_FE_IE_IRAT_MEASUREMENT_CONFIGURATION] = { TLV_TYPE_TLV }, + [GSM0808_FE_IE_SOURCE_CELL_ID] = { TLV_TYPE_TLV }, + [GSM0808_FE_IE_IRAT_MEASUREMENT_CONFIGURATION_EXTENDED_E_ARFCNS] = { TLV_TYPE_TLV }, + [GSM0808_FE_IE_VGCS_TALKER_MODE] = { TLV_TYPE_TLV }, + [GSM0808_FE_IE_LAST_USED_EUTRAN_PLMN_ID] = { TLV_TYPE_FIXED, 3 }, + }, +}; + const struct value_string gsm0406_dlci_sapi_names[] = { { DLCI_SAPI_RR_MM_CC, "RR/MM/CC" }, { DLCI_SAPI_SMS, "SMS" }, @@ -1671,7 +2434,9 @@ static const struct value_string gsm0808_msgt_names[] = { { BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_RQST, "VGCS/VBS ASSIGN REQ" }, { BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_RESULT, "VGCS/VBS ASSIGN RES" }, { BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_FAILURE, "VGCS/VBS ASSIGN FAIL" }, + { BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_STATUS, "VGCS/VBS ASSIGN STATUS" }, { BSS_MAP_MSG_VGCS_VBS_QUEUING_INDICATION, "VGCS/VBS QUEUING IND" }, + { BSS_MAP_MSG_VGCS_VBS_AREA_CELL_INFO, "VGCS/VBS AREA CELL INFO" }, { BSS_MAP_MSG_UPLINK_RQST, "UPLINK REQ" }, { BSS_MAP_MSG_UPLINK_RQST_ACKNOWLEDGE, "UPLINK REQ ACK" }, { BSS_MAP_MSG_UPLINK_RQST_CONFIRMATION, "UPLINK REQ CONF" }, @@ -1680,11 +2445,12 @@ static const struct value_string gsm0808_msgt_names[] = { { BSS_MAP_MSG_UPLINK_RELEASE_CMD, "UPLINK REL CMD" }, { BSS_MAP_MSG_UPLINK_SEIZED_CMD, "UPLINK SEIZED CMD" }, { BSS_MAP_MSG_VGCS_ADDL_INFO, "VGCS ADDL INFO" }, + { BSS_MAP_MSG_VGCS_SMS, "VGCS SMS" }, { BSS_MAP_MSG_NOTIFICATION_DATA, "NOTIF DATA" }, { BSS_MAP_MSG_UPLINK_APP_DATA, "UPLINK APP DATA" }, { BSS_MAP_MSG_LCLS_CONNECT_CTRL, "LCLS-CONNECT-CONTROL" }, - { BSS_MAP_MSG_LCLS_CONNECT_CTRL_ACK, "CLS-CONNECT-CONTROL-ACK" }, + { BSS_MAP_MSG_LCLS_CONNECT_CTRL_ACK, "LCLS-CONNECT-CONTROL-ACK" }, { BSS_MAP_MSG_LCLS_NOTIFICATION, "LCLS-NOTIFICATION" }, { 0, NULL } @@ -1718,6 +2484,7 @@ const struct value_string gsm0808_speech_codec_type_names[] = { { GSM0808_SCT_HR3, "HR3" }, { GSM0808_SCT_HR4, "HR4" }, { GSM0808_SCT_HR6, "HR6" }, + { GSM0808_SCT_EXT, "Codec Extension" }, { GSM0808_SCT_CSD, "CSD" }, { 0, NULL } }; @@ -1924,4 +2691,101 @@ const struct value_string gsm0808_lcls_status_names[] = { { 0, NULL } }; +/* Convert one S0-S15 bit to its set of AMR modes, for HR AMR and FR AMR. + * This is 3GPP TS 28.062 Table 7.11.3.1.3-2: "Preferred Configurations", with some configurations removed as specified + * in 3GPP TS 48.008 3.2.2.103: + * + * FR_AMR is coded ‘0011’. + * S11, S13 and S15 are reserved and coded with zeroes. + * + * HR_AMR is coded ‘0100’. + * S6 - S7 and S11 – S15 are reserved and coded with zeroes. + * + * Meaning: for FR, exclude all Optimisation Mode configurations. + * For HR, exclude all that are not supported by HR AMR -- drop all that include at least one of + * 10.2 or 12.2. + * + * Also, for HR, drop 12.2k from S1. + * + * The first array dimension is 0 for half rate and 1 for full rate. + * The second array dimension is the configuration number (0..15) aka Sn. + * The values are bitmask combinations of (1 << GSM0808_AMR_MODE_nnnn). + * + * For example, accumulate all modes that are possible in a given my_s15_s0: + * + * uint8_t modes = 0; + * for (s_bit = 0; s_bit < 15; s_bit++) + * if (my_s15_s0 & (1 << s_bit)) + * modes |= gsm0808_amr_modes_from_cfg[full_rate ? 1 : 0][s_bit]; + * for (i = 0; i < 8; i++) + * if (modes & (1 << i)) + * printf(" %s", gsm0808_amr_mode_name(i)); + */ +const uint8_t gsm0808_amr_modes_from_cfg[2][16] = { +#define B(X) (1 << (GSM0808_AMR_MODE_##X)) + /* HR */ + { + /* Sn = modes */ + [0] = B(4_75), + [1] = B(4_75) | B(5_90) | B(7_40), + [2] = B(5_90), + [3] = B(6_70), + [4] = B(7_40), + [5] = B(7_95), + [6] = 0, + [7] = 0, + + [8] = B(4_75) | B(5_90), + [9] = B(4_75) | B(5_90) | B(6_70), + [10] = B(4_75) | B(5_90) | B(6_70) | B(7_40), + [11] = 0, + [12] = 0, + [13] = 0, + [14] = 0, + [15] = 0, + }, + /* FR */ + { + /* Sn = modes */ + [0] = B(4_75), + [1] = B(4_75) | B(5_90) | B(7_40) | B(12_2), + [2] = B(5_90), + [3] = B(6_70), + [4] = B(7_40), + [5] = B(7_95), + [6] = B(10_2), + [7] = B(12_2), + + [8] = B(4_75) | B(5_90), + [9] = B(4_75) | B(5_90) | B(6_70), + [10] = B(4_75) | B(5_90) | B(6_70) | B(7_40), + [11] = 0, + [12] = B(4_75) | B(5_90) | B(6_70) | B(10_2), + [13] = 0, + [14] = B(4_75) | B(5_90) | B(7_95) | B(12_2), + [15] = 0, + } +}; + +/* AMR mode names from GSM0808_AMR_MODE_*, for use with gsm0808_amr_modes_from_cfg. + * + * For example: + * printf("S9: "); + * uint8_t s9_modes = gsm0808_amr_modes_from_cfg[full_rate ? 1 : 0][9]; + * for (bit = 0; bit < 8; bit++) + * if (s9_modes & (1 << bit)) + * printf("%s,", gsm0808_amr_mode_name(bit)); + */ +const struct value_string gsm0808_amr_mode_names[] = { + { GSM0808_AMR_MODE_4_75, "4.75" }, + { GSM0808_AMR_MODE_5_15, "5.15" }, + { GSM0808_AMR_MODE_5_90, "5.90" }, + { GSM0808_AMR_MODE_6_70, "6.70" }, + { GSM0808_AMR_MODE_7_40, "7.40" }, + { GSM0808_AMR_MODE_7_95, "7.95" }, + { GSM0808_AMR_MODE_10_2, "10.2" }, + { GSM0808_AMR_MODE_12_2, "12.2" }, + {} +}; + /*! @} */ |