| /* Encoding/Decoding routines for GSM System Information messages |
| * according to 3GPP TS 44.018 Version 12.3.0 Release 12 |
| * |
| * (C) 2018 Harald Welte <laforge@gnumonks.org> |
| * All rights reserved. |
| * |
| * Released under the terms of GNU General Public License, Version 2 or |
| * (at your option) any later version. |
| * |
| * SPDX-License-Identifier: GPL-2.0-or-later |
| */ |
| |
| module GSM_SystemInformation { |
| |
| import from General_Types all; |
| import from GSM_Types all; |
| import from GSM_RR_Types all; |
| import from GSM_RestOctets all; |
| import from Osmocom_Types all; |
| |
| type union ArfcnOrMaio { |
| uint12_t arfcn, |
| MaioHsn maio_hsn |
| } with { variant "" }; |
| |
| /* 24.008 10.5.1.1 */ |
| type uint16_t SysinfoCellIdentity; |
| |
| /* 44.018 10.5.2.1b */ |
| type octetstring CellChannelDescription with { variant "FIELDLENGTH(16)" }; |
| |
| /* 44.018 10.5.2.3 */ |
| type enumerated CellOptions_DTX { |
| MS_MAY_USE_UL_DTX ('00'B), |
| MS_SHALL_USE_UL_DTX ('01'B), |
| MS_SHALL_NOT_USE_UL_DTX ('10'B) |
| } with { variant "FIELDLENGTH(2)" }; |
| type record CellOptions { |
| boolean dn_ind, |
| boolean pwrc, |
| CellOptions_DTX dtx, |
| uint4_t radio_link_tout_div4 |
| } with { variant "" }; |
| |
| /* 44.018 10.5.2.3a */ |
| type record CellOptionsSacch { |
| BIT1 dtx_ext, |
| boolean pwrc, |
| BIT2 dtx, |
| BIT4 radio_link_timeout |
| } with { variant "" }; |
| |
| /* 44.018 10.5.2.4 */ |
| type record CellSelectionParameters { |
| uint3_t cell_resel_hyst_2dB, |
| uint5_t ms_txpwr_max_cch, |
| BIT1 acs, |
| boolean neci, |
| uint6_t rxlev_access_min |
| } with { variant "" }; |
| |
| /* 44.018 10.5.2.11 */ |
| type enumerated CtrlChanDesc_CC { |
| CCHAN_DESC_1CCCH_NOT_COMBINED ('000'B), |
| CCHAN_DESC_1CCCH_COMBINED ('001'B), |
| CCHAN_DESC_2CCCH_NOT_COMBINED ('010'B), |
| CCHAN_DESC_3CCCH_NOT_COMBINED ('100'B), |
| CCHAN_DESC_4CCCH_NOT_COMBINED ('110'B) |
| } with { variant "FIELDLENGTH(3)" }; |
| type enumerated CBQ3 { |
| CBQ3_IU_MODE_NOT_SUPPORTED ('00'B), |
| CBQ3_IU_MODE_MS_BARRED ('01'B), |
| CBQ3_IU_MODE_NOT_BARRED ('10'B) |
| } with { variant "FIELDLENGTH(2)" }; |
| type record ControlChannelDescription { |
| boolean msc_r99, |
| boolean att, |
| uint3_t bs_ag_blks_res, |
| CtrlChanDesc_CC ccch_conf, |
| boolean si22ind, |
| CBQ3 cbq3, |
| BIT2 spare, |
| uint3_t bs_pa_mfrms, /* off by 2 */ |
| uint8_t t3212 |
| } with { variant "" }; |
| |
| template ControlChannelDescription t_ControlChannelDescription := { ?, ?, ?, ?, ?, ?, '00'B, ?, ? }; |
| |
| /* 44.018 10.5.2.22 */ |
| type octetstring NeighbourCellDescription with { variant "FIELDLENGTH(16)" }; |
| |
| /* 44.018 10.5.2.22a */ |
| type octetstring NeighbourCellDescription2 with { variant "FIELDLENGTH(16)" }; |
| |
| type bitstring AccessControlClass with { variant "FIELDLENGTH(16), BYTEORDER(last)" }; |
| |
| /* 44.018 10.5.2.29 */ |
| type enumerated RachCtrlPar_MR { |
| RACH_MAX_RETRANS_1 ('00'B), |
| RACH_MAX_RETRANS_2 ('01'B), |
| RACH_MAX_RETRANS_4 ('10'B), |
| RACH_MAX_RETRANS_7 ('11'B) |
| } with { variant "FIELDLENGTH(2)" }; |
| type record RachControlParameters { |
| RachCtrlPar_MR max_retrans, |
| BIT4 tx_integer, |
| boolean cell_barr_access, |
| boolean re_not_allowed, |
| AccessControlClass acc |
| } with { variant (acc) "FIELDLENGTH(16)" }; |
| |
| /* 44.018 9.1.31 */ |
| type record SystemInformationType1 { |
| CellChannelDescription cell_chan_desc, |
| RachControlParameters rach_control, |
| RestOctets rest_octets length(0..1) |
| } with { variant "" }; |
| |
| /* 44.018 9.1.32 */ |
| type record SystemInformationType2 { |
| NeighbourCellDescription bcch_freq_list, |
| BIT8 ncc_permitted, |
| RachControlParameters rach_control |
| } with { variant "" }; |
| |
| /* 44.018 9.1.33 */ |
| type record SystemInformationType2bis { |
| NeighbourCellDescription extd_bcch_freq_list, |
| RachControlParameters rach_control, |
| RestOctets rest_octets length(0..1) |
| } with { variant "" }; |
| |
| /* 44.018 9.1.34 */ |
| type record SystemInformationType2ter { |
| NeighbourCellDescription2 extd_bcch_freq_list, |
| RestOctets rest_octets length(0..4) |
| } with { variant "" }; |
| |
| type record SystemInformationType2quater { |
| SI2quaterRestOctets rest_octets |
| } with { variant "" }; |
| |
| /* 44.018 9.1.35 */ |
| type record SystemInformationType3 { |
| SysinfoCellIdentity cell_id, |
| LocationAreaIdentification lai, |
| ControlChannelDescription ctrl_chan_desc, |
| CellOptions cell_options, |
| CellSelectionParameters cell_sel_par, |
| RachControlParameters rach_control, |
| SI3RestOctets rest_octets |
| } with { variant "" }; |
| |
| template SystemInformationType3 t_SI3 := { |
| cell_id := ?, |
| lai := ?, |
| ctrl_chan_desc := t_ControlChannelDescription, |
| cell_options := ?, |
| cell_sel_par := ?, |
| rach_control := ?, |
| rest_octets := ? |
| }; |
| |
| |
| /* 44.018 9.1.36 */ |
| type record SystemInformationType4 { |
| LocationAreaIdentification lai, |
| CellSelectionParameters cell_sel_par, |
| RachControlParameters rach_control, |
| ChannelDescriptionTV cbch_chan_desc optional, |
| MobileAllocationTLV cbch_mobile_alloc optional, |
| SI4RestOctets rest_octets /* see 10.5.2.35 */ |
| } with { variant "TAG(cbch_chan_desc, iei = '64'O; cbch_mobile_alloc, iei = '72'O)" }; |
| |
| /* 44.018 9.1.37 */ |
| type record SystemInformationType5 { |
| NeighbourCellDescription bcch_freq_list |
| } with { variant "" }; |
| |
| /* 44.018 9.1.38 */ |
| type record SystemInformationType5bis { |
| NeighbourCellDescription extd_bcch_freq_list |
| } with { variant "" }; |
| |
| /* 44.018 9.1.39 */ |
| type record SystemInformationType5ter { |
| NeighbourCellDescription2 extd_bcch_freq_list |
| } with { variant "" }; |
| |
| /* 44.018 9.1.40 */ |
| type record SystemInformationType6 { |
| SysinfoCellIdentity cell_id, |
| LocationAreaIdentification lai, |
| CellOptionsSacch cell_options, |
| BIT8 ncc_permitted, |
| SI6RestOctets rest_octets |
| } with { variant "" }; |
| |
| /* 44.018 9.1.43a */ |
| type record SystemInformationType13 { |
| SI13RestOctets rest_octets |
| } with { variant "" }; |
| |
| type union SystemInformationUnion { |
| SystemInformationType1 si1, |
| SystemInformationType2 si2, |
| SystemInformationType2bis si2bis, |
| SystemInformationType2ter si2ter, |
| SystemInformationType2quater si2quater, |
| SystemInformationType3 si3, |
| SystemInformationType4 si4, |
| SystemInformationType5 si5, |
| SystemInformationType5bis si5bis, |
| SystemInformationType5ter si5ter, |
| SystemInformationType6 si6, |
| SystemInformationType13 si13, |
| octetstring other |
| } with { variant "" }; |
| |
| type record SystemInformation { |
| RrHeader header, |
| SystemInformationUnion payload |
| } with { variant (payload) "CROSSTAG(si1, header.message_type = SYSTEM_INFORMATION_TYPE_1; |
| si2, header.message_type = SYSTEM_INFORMATION_TYPE_2; |
| si2bis, header.message_type = SYSTEM_INFORMATION_TYPE_2bis; |
| si2ter, header.message_type = SYSTEM_INFORMATION_TYPE_2ter; |
| si2quater, header.message_type = SYSTEM_INFORMATION_TYPE_2quater; |
| si3, header.message_type = SYSTEM_INFORMATION_TYPE_3; |
| si4, header.message_type = SYSTEM_INFORMATION_TYPE_4; |
| si5, header.message_type = SYSTEM_INFORMATION_TYPE_5; |
| si5bis, header.message_type = SYSTEM_INFORMATION_TYPE_5bis; |
| si5ter, header.message_type = SYSTEM_INFORMATION_TYPE_5ter; |
| si6, header.message_type = SYSTEM_INFORMATION_TYPE_6; |
| si13, header.message_type = SYSTEM_INFORMATION_TYPE_13; |
| other, OTHERWISE; |
| )" }; |
| |
| external function enc_SystemInformationNoPad(in SystemInformation si) return octetstring |
| with { extension "prototype(convert) encode(RAW)" }; |
| external function dec_SystemInformation(in octetstring stream) return SystemInformation |
| with { extension "prototype(convert) decode(RAW)" }; |
| |
| /* Due to a buggy nature of TITAN's padding attributes, we have to apply padding manually. */ |
| function enc_SystemInformation(in SystemInformation si) return octetstring |
| { |
| var octetstring si_enc := enc_SystemInformationNoPad(si); |
| |
| /* Resulting message length depends on SI Type */ |
| select (si.header.message_type) { |
| case (SYSTEM_INFORMATION_TYPE_5, |
| SYSTEM_INFORMATION_TYPE_5bis, |
| SYSTEM_INFORMATION_TYPE_5ter) { |
| /* SACCH: no Rest Octets, return 'as-is' */ |
| return si_enc; |
| } |
| case (SYSTEM_INFORMATION_TYPE_6) { |
| /* SACCH: pad to 19 octets, leave room for L1/LAPDm headers */ |
| return f_pad_oct(si_enc, 19, '2B'O); |
| } |
| case else { |
| /* BCCH: pad to 23 octets */ |
| return f_pad_oct(si_enc, 23, '2B'O); |
| } |
| } |
| } |
| |
| external function dec_SystemInformationSafeBT(in octetstring stream, out SystemInformation si) |
| return integer /* Decoding result: successful (0) or unsuccessful (1) */ |
| with { extension "prototype(backtrack) decode(RAW)" }; |
| |
| /* Some types of System Information (mostly the Rest Octets) are not fully implemented, |
| * so calling the generic dec_SystemInformation() may result in a DTE. This function |
| * additionally checks RR Protocol Discriminator, and should be used in the most cases. */ |
| function dec_SystemInformationSafe(in octetstring stream, out SystemInformation si) |
| return integer { |
| /* Try to decode a given octetstring as System Information */ |
| if (dec_SystemInformationSafeBT(stream, si) != 0) { |
| log("Failed to decode (RR) System Information: ", stream); |
| return 1; |
| } |
| |
| /* Check the protocol discriminator (we expect RR messages) */ |
| if (si.header.rr_protocol_discriminator != bit2int('0110'B)) { |
| log("Protocol discriminator is not RR (!= '0110'B): ", |
| si.header.rr_protocol_discriminator); |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| } with { encode "RAW"; variant "FIELDORDER(msb)" } |