/* 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)" }