/* Encoding/Decoding routines for GSM System Information messages * according to 3GPP TS 44.018 Version 12.3.0 Release 12 * * (C) 2017-2019 Harald Welte * 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_RR_Types { import from General_Types all; import from Osmocom_Types all; import from GSM_Types all; import from RLCMAC_CSN1_Types all; /* Table 10.4.1 of Section 10.4 / 3GPP TS 44.018 */ type enumerated RrMessageType { ADDITIONAL_ASSIGNMENT ('00111011'B), IMMEDIATE_ASSIGNMENT ('00111111'B), IMMEDIATE_ASSIGNMENT_EXTENDED ('00111001'B), IMMEDIATE_ASSIGNMENT_REJECT ('00111010'B), IMMEDIATE_PACKET_ASSIGNMENT ('01101001'B), CIPHERING_MODE_COMMAND ('00110101'B), CIPHERING_MODE_COMPLETE ('00110010'B), CONFIGURATION_CHANGE_COMMAND ('00110000'B), CONFIGURATION_CHANGE_ACK ('00110001'B), CONFIGURATION_CHANGE_REJECT ('00110011'B), ASSIGNMENT_COMMAND ('00101110'B), ASSIGNMENT_COMPLETE ('00101001'B), ASSIGNMENT_FAILURE ('00101111'B), HANDOVER_COMMAND ('00101011'B), HANDOVER_COMPLETE ('00101100'B), HANDOVER_FAILURE ('00101000'B), PHYSICAL_INFORMATION ('00101101'B), CHANNEL_RELEASE ('00001101'B), PARTIAL_RELEASE ('00001010'B), PARTIAL_RELEASE_COMPLETE ('00001111'B), PAGING_REQUEST_TYPE_1 ('00100001'B), PAGING_REQUEST_TYPE_2 ('00100010'B), PAGING_REQUEST_TYPE_3 ('00100100'B), PAGING_RESPONSE ('00100111'B), NOTIFICATION_NCH ('00100000'B), NOTIFICATION_RESPOSNE ('00100110'B), SYSTEM_INFORMATION_TYPE_8 ('00011000'B), SYSTEM_INFORMATION_TYPE_1 ('00011001'B), SYSTEM_INFORMATION_TYPE_2 ('00011010'B), SYSTEM_INFORMATION_TYPE_3 ('00011011'B), SYSTEM_INFORMATION_TYPE_4 ('00011100'B), SYSTEM_INFORMATION_TYPE_5 ('00011101'B), SYSTEM_INFORMATION_TYPE_6 ('00011110'B), SYSTEM_INFORMATION_TYPE_7 ('00011111'B), SYSTEM_INFORMATION_TYPE_2bis ('00000010'B), SYSTEM_INFORMATION_TYPE_2ter ('00000011'B), SYSTEM_INFORMATION_TYPE_2quater ('00000111'B), SYSTEM_INFORMATION_TYPE_5bis ('00000101'B), SYSTEM_INFORMATION_TYPE_5ter ('00000110'B), SYSTEM_INFORMATION_TYPE_9 ('00000100'B), SYSTEM_INFORMATION_TYPE_13 ('00000000'B), SYSTEM_INFORMATION_TYPE_16 ('00111101'B), SYSTEM_INFORMATION_TYPE_17 ('00111110'B), CHANNEL_MODE_MODIFY ('00010000'B), RR_STATUS ('00010010'B), CHANNEL_MODE_MODIFY_ACKNOWLEDGE ('00010111'B), FREQUENCY_REDEFINITION ('00010100'B), MEASUREMENT_REPORT ('00010101'B), CLASSMARK_CHANGE ('00010110'B), CLASSMARK_ENQUIRY ('00010011'B), EXTENDED_MEASUREMENT_REPORT ('00110110'B), EXTENDED_MEASUREMENT_ORDER ('00110111'B), GPRS_SUSPENSION_REQUEST ('00110100'B), //MBMS_ANNOUNCEMENT ('00010110'B), duplicate? //SERVICE_INFORMATION ('00110110'B), duplicate? APPLICATION_INFORMATION ('00111000'B), SYSTEM_INFORMATION_TYPE_14 ('00000001'B), SYSTEM_INFORMATION_TYPE_15 ('01000011'B), SYSTEM_INFORMATION_TYPE_18 ('01000000'B), SYSTEM_INFORMATION_TYPE_19 ('01000001'B), SYSTEM_INFORMATION_TYPE_20 ('01000010'B), SYSTEM_INFORMATION_TYPE_13alt ('01000100'B), SYSTEM_INFORMATION_TYPE_2n ('01000101'B), SYSTEM_INFORMATION_TYPE_21 ('01000110'B), SYSTEM_INFORMATION_TYPE_22 ('01000111'B), SYSTEM_INFORMATION_TYPE_23 ('01001111'B), DTM_ASSIGNMENT_FAILURE ('01001000'B), DTM_REJECT ('01001001'B), DTM_REQUEST ('01001010'B), PACKET_ASSIGNMENT ('01001011'B), DTM_ASSIGNMENT_COMMAND ('01001100'B), DTM_INFORMATION ('01001101'B), PACKET_INFORMATION ('01001110'B), UTRAN_CLASSMARK_CHANGE ('01100000'B), CDMA2000_CLASSMARK_CHANGE ('01100010'B), INTERSYS_TO_UTRAN_HO_CMD ('01100011'B), INTERSYS_TO_CDMA2000_HO_CMD ('01100100'B), GERAN_IU_MODE_CLASSMARK_CHG ('01100101'B), INTERSYS_TO_EUTRAN_HO_CMD ('01100110'B) } with { variant "FIELDLENGTH(8)" }; type octetstring RestOctets with { variant "PADDING(yes), PADDING_PATTERN('00101011'B)" }; type hexstring GsmBcdString with { variant "HEXORDER(low)" }; type GsmBcdString BcdMccMnc with { variant "FIELDLENGTH(6)" }; type record L2PseudoLength { uint6_t l2_plen, BIT2 zero_one } with { variant "" }; template L2PseudoLength tr_L2Pseudolength(template uint6_t len) := { l2_plen := len, zero_one := '01'B }; template (value) L2PseudoLength ts_L2Pseudolength(uint6_t len) := { l2_plen := len, zero_one := '01'B }; type record RrHeader { L2PseudoLength l2_plen, uint4_t skip_indicator, uint4_t rr_protocol_discriminator, RrMessageType message_type } with { variant "" }; template RrHeader t_RrHeader(RrMessageType msg_type, template uint6_t len) := { l2_plen := tr_L2Pseudolength(len), skip_indicator := 0, rr_protocol_discriminator := 6, message_type := msg_type }; template (value) RrHeader ts_RrHeader(RrMessageType msg_type, uint6_t len) := { l2_plen := ts_L2Pseudolength(len), skip_indicator := 0, rr_protocol_discriminator := 6, message_type := msg_type }; type record RrL3Header { uint4_t skip_indicator, uint4_t rr_protocol_discriminator, RrMessageType message_type } with { variant "" }; template RrL3Header t_RrL3Header(RrMessageType msg_type) := { skip_indicator := 0, rr_protocol_discriminator := 6, message_type := msg_type } /* TS 44.004 7.2.1 */ type record SacchL1Header { uint2_t reserved, boolean fpc, uint5_t ms_power_lvl, uint8_t actual_ta } with { variant "FIELDORDER(msb)" }; template (value) SacchL1Header ts_SacchL1Header(uint5_t ms_power_lvl, boolean fpc, uint8_t actual_ta) := { reserved := 0, fpc := fpc, ms_power_lvl := ms_power_lvl, actual_ta := actual_ta }; type record MaioHsn { } with { variant "" }; /* TS 24.008 10.5.1.1 */ type uint16_t CellIdentity; /* TS 24.008 10.5.1.2 */ type uint4_t CipheringKeySeqNr (0..7); /* 24.008 10.5.1.3 */ type record LocationAreaIdentification { BcdMccMnc mcc_mnc, uint16_t lac } with { variant "" }; /* TS 24.008 10.5.1.4 */ type enumerated MobileIdentityType { MI_TYPE_NONE (0), MI_TYPE_IMSI, MI_TYPE_IMEI, MI_TYPE_IMEISV, MI_TYPE_TMSI, MI_TYPE_TMGI } with { variant "FIELDLENGTH(3)" }; type record MobileIdentityBCD { MobileIdentityType mi_type (MI_TYPE_IMSI, MI_TYPE_IMEI, MI_TYPE_IMEISV), boolean odd, hexstring digits } with { variant "FIELDORDER(lsb)" }; type record MobileIdentityTMSI { BIT4 pad ('1111'B), boolean odd (false), MobileIdentityType mi_type (MI_TYPE_TMSI), GsmTmsi tmsi } with { variant "FIELDORDER(lsb)" }; type record MobileIdentityNone { BIT4 pad ('1111'B), boolean odd (false), MobileIdentityType mi_type (MI_TYPE_NONE) } with { variant "FIELDORDER(lsb)" }; type union MobileIdentity { MobileIdentityBCD imsi, MobileIdentityBCD imei, MobileIdentityBCD imeisv, MobileIdentityTMSI tmsi, MobileIdentityNone unused } with { variant "TAG(imsi, mi_type = MI_TYPE_IMSI; imei, mi_type = MI_TYPE_IMEI; imeisv, mi_type = MI_TYPE_IMEISV; tmsi, mi_type = MI_TYPE_TMSI; unused, mi_type = MI_TYPE_NONE)" variant "FIELDORDER(lsb)" }; /* TS 24.008 10.5.1.4 "Mobile Identity" */ type record MobileIdentityLV { uint8_t len, MobileIdentity mi } with { variant (len) "LENGTHTO(mi)" }; type record MobileIdentityTLV { uint8_t tag, uint8_t len, MobileIdentity mi } with { variant (len) "LENGTHTO(mi)" }; /* TS 24.008 10.5.1.5 */ type record MsClassmark1 { BIT1 spare, uint2_t rev_level, boolean es_ind, boolean a51, uint3_t rf_pwr_cap } with { variant "" }; /* TS 24.008 10.5.1.6 */ type record MsClassmark2 { BIT1 spare, uint2_t rev_level, boolean es_ind, boolean a51, uint3_t rf_pwr_cap, BIT1 spare1, boolean ps_cap, uint2_t ss_screen_ind, boolean sm_cap, boolean vbs, boolean vgcs, boolean fc, boolean cm3, BIT1 spare2, boolean lcsva_cap, boolean ucs2, boolean solsa, boolean cmsp, boolean a53, boolean a52 } with { variant "" }; type record MsClassmark2LV { uint8_t len, MsClassmark2 cm2 } with { variant (len) "LENGTHTO(cm2)" }; /* 44.018 10.5.2.5 */ type record ChannelDescription { RslChannelNr chan_nr, uint3_t tsc, boolean h, uint12_t arfcn optional, MaioHsn maio_hsn optional } with { variant (arfcn) "PRESENCE(h = false)" variant (maio_hsn) "PRESENCE(h = true)" }; type record ChannelDescriptionTV { OCT1 iei, ChannelDescription v } with { variant "" }; /* 10.5.2.21 */ type record MobileAllocation { uint8_t len, bitstring ma } with { variant (len) "LENGTHTO(ma)" }; /* 10.5.2.25a */ type record PktChDesc0Ind { uint6_t maio, BIT1 ma_number_ind, BIT1 change_mark1_valid, BIT2 change_mark1 } with { variant "" }; type record PktChDesc0 { BIT1 hopping, BIT1 spare ('0'B), uint10_t arfcn optional, PktChDesc0Ind indirect optional } with { variant (arfcn) "PRESENCE(hopping = '0'B)" variant (indirect) "PRESENCE(hopping = '1'B)" }; type record PktChDesc1 { uint6_t maio, uint6_t hsn } with { variant "" }; type record PacketChannelDescription { uint5_t channel_Type_spare, uint3_t tn, uint3_t tsc, BIT1 presence, PktChDesc0 zero optional, PktChDesc1 one optional } with { variant (zero) "PRESENCE(presence = '0'B)" variant (one) "PRESENCE(presence = '1'B)" }; /* 10.5.2.25b */ type record DedicatedModeOrTbf { BIT1 spare, boolean tma, boolean downlink, boolean tbf } with { variant "" }; /* 10.5.2.26 */ type enumerated PageMode { PAGE_MODE_NORMAL, PAGE_MODE_EXTENDED, PAGE_MODE_REORGANIZATION, PAGE_MODE_SAME_AS_BEFORE } with { variant "FIELDLENGTH(4)" }; /* 10.5.2.30 */ type record RequestReference { bitstring ra length(8), uint5_t t1p, uint6_t t3, uint5_t t2 } with { variant "" }; template RequestReference t_RequestReference(template bitstring ra, template uint5_t t1p, template uint6_t t3, template uint5_t t2) := { ra := ra, t1p := t1p, t3 := t3, t2 := t2 } /* compute the expected request reference for given RA + FN */ function f_compute_ReqRef(uint8_t ra, GsmFrameNumber fn) return RequestReference { var RequestReference req_ref := { ra := int2bit(ra, 8) }; req_ref.t1p := (fn / 1326) mod 32; req_ref.t2 := fn mod 26; req_ref.t3 := fn mod 51; return req_ref } function tr_compute_ReqRef(template uint8_t ra, template GsmFrameNumber fn) return template RequestReference { var template RequestReference req_ref; if (istemplatekind(ra, "?")) { req_ref.ra := ?; } else { req_ref.ra := int2bit(valueof(ra), 8); } if (istemplatekind(fn, "?")) { req_ref.t1p := ?; req_ref.t2 := ?; req_ref.t3 := ?; } else { var GsmFrameNumber fn_v := valueof(fn); req_ref.t1p := (fn_v / 1326) mod 32; req_ref.t2 := fn_v mod 26; req_ref.t3 := fn_v mod 51; } return req_ref; } /* 10.5.2.40 */ type integer TimingAdvance (0..219); /* 10.5.2.43 */ type uint8_t WaitIndication; /* 10.5.2.76 */ type record FeatureIndicator { BIT2 spare, boolean cs_ir, boolean ps_ir } with { variant "" }; /* 24.008 10.5.5.6 */ type record DrxParameter { uint8_t split_pg_cycle_code, uint4_t drx_cycle_len_coeff, boolean split_on_ccch, uint3_t non_drx_timer } with { variant "" }; /* 24.008 10.5.5.15 */ type record RoutingAreaIdentification { LocationAreaIdentification lai, uint8_t rac } with { variant "" }; external function enc_RoutingAreaIdentification(RoutingAreaIdentification rai) return octetstring with { extension "prototype(convert)" extension "encode(RAW)" } /* 44.018 10.5.2.16 */ type record IaRestOctHL { uint6_t freq_par_len, BIT2 padding ('00'B) optional, uint6_t maio optional, octetstring mobile_allocation optional } with { variant (freq_par_len) "LENGTHTO(mobile_allocation,maio,padding)" /* variant (padding) "PRESENCE(freq_par_len != 0)" variant (maio) "PRESENCE(freq_par_len != 0)" variant (mobile_allocation) "PRESENCE(freq_par_len != 0)" */ }; type record SecondPartAssign { BIT1 r99, /* H / L */ BIT1 presence optional, BIT5 ext_ra optional } with { /* TODO: use 'CSN.1 L/H' attribute here */ variant (presence) "PRESENCE(r99 = '1'B)" /* H */ variant (ext_ra) "PRESENCE(presence = '1'B)" }; type union PacketUlDlAssignUnion { PacketUlAssign ul, PacketDlAssign dl }; type record PacketUlDlAssign { BIT1 ass_disc, PacketUlDlAssignUnion ass } with { variant (ass) "CROSSTAG(dl, ass_disc = '1'B; ul, ass_disc = '0'B)" }; type union PacketAssignUnion { SecondPartAssign spa, PacketUlDlAssign uldl }; type record IaRestOctHH { /* Packet Assignment discriminator: * Packet Uplink / Downlink Assignment (0) * Second Part Packet Assignment (1) */ BIT1 pa_disc, PacketAssignUnion pa } with { variant (pa) "CROSSTAG(spa, pa_disc = '1'B; uldl, pa_disc = '0'B)" }; type record PacketUlAssignDyn { uint5_t tfi_assignment, BIT1 polling, BIT1 spare ('0'B), uint3_t usf, BIT1 usf_granularity, BIT1 p0_present, uint4_t p0 optional, BIT1 pr_mode optional, ChCodingCommand ch_coding_cmd, BIT1 tlli_block_chan_coding, BIT1 alpha_present, uint4_t alpha optional, uint5_t gamma, BIT1 ta_index_present, uint4_t ta_index optional, BIT1 tbf_starting_time_present, uint16_t tbf_starting_time optional } with { variant (p0) "PRESENCE(p0_present = '1'B)" variant (pr_mode) "PRESENCE(p0_present = '1'B)" variant (alpha) "PRESENCE(alpha_present = '1'B)" variant (ta_index) "PRESENCE(ta_index_present = '1'B)" variant (tbf_starting_time) "PRESENCE(tbf_starting_time_present = '1'B)" }; type record PacketUlAssignSgl { BIT1 alpha_present, uint4_t alpha optional, uint5_t gamma, BIT2 padding ('01'B), uint16_t tbf_starting_time /* TODO: P0 / PR_MODE */ } with { variant (alpha) "PRESENCE(alpha_present = '1'B)" }; type record PacketUlAssign { BIT1 presence, PacketUlAssignDyn dynamic optional, PacketUlAssignSgl single optional /* TODO: Estended RA, PFI */ } with { variant (dynamic) "PRESENCE(presence = '1'B)" variant (single) "PRESENCE(presence = '0'B)" }; type record PacketDlAssG1 { uint5_t tfi_assignment, BIT1 rlc_mode, BIT1 alpha_present, uint4_t alpha optional, uint5_t gamma, BIT1 polling, BIT1 ta_valid } with { variant "" }; type record PacketDlAssign { GprsTlli tlli, BIT1 group1_present, PacketDlAssG1 group1 optional, BIT1 ta_index_present, uint4_t ta_index optional, BIT1 tbf_starting_time_present, uint16_t tbf_starting_time optional, BIT1 p0_present, uint4_t p0 optional, BIT1 pr_mode optional /* TODO: EGPRS window size, etc. */ } with { variant (group1) "PRESENCE(group1_present = '1'B)" variant (ta_index) "PRESENCE(ta_index_present = '1'B)" variant (tbf_starting_time) "PRESENCE(tbf_starting_time_present = '1'B)" variant (p0) "PRESENCE(p0_present = '1'B)" variant (pr_mode) "PRESENCE(p0_present = '1'B)" }; type record IaRestOctLL { BIT1 compressed_irat_ho_info_ind } with { variant "" }; type octetstring EgprsUlAss; /* TODO */ type octetstring MblkDlAss; /* TODO */ type record IaRestOctLH { BIT2 presence, EgprsUlAss egprs_ul optional, MblkDlAss multiblock_dl_ass optional } with { variant (egprs_ul) "PRESENCE(presence = '00'B)" variant (multiblock_dl_ass) "PRESENCE(presence = '01'B)" }; type record IaRestOctets { BIT2 presence, IaRestOctLL ll optional, IaRestOctLH lh optional, IaRestOctHL hl optional, IaRestOctHH hh optional } with { variant (ll) "PRESENCE(presence = '00'B)" variant (lh) "PRESENCE(presence = '01'B)" variant (hl) "PRESENCE(presence = '10'B)" variant (hh) "PRESENCE(presence = '11'B)" variant "PADDING(yes), PADDING_PATTERN('00101011'B)" }; type record MeasurementResults { BIT1 ba_used, BIT1 dtx_used, uint6_t rxlev_full_srv_cell, BIT1 threeg_ba_used, BIT1 meas_valid, uint6_t rxlev_sub_srv_cell, BIT1 si23_ba_used, uint3_t rxqual_full_srv_cell, uint3_t rxqual_sub_srv_cell, uint3_t no_ncell_m, NcellReports ncell_reports optional } with { variant (no_ncell_m) "LENGTHTO(ncell_reports)" variant (no_ncell_m) "UNIT(elements)" variant "PADDING(yes)" variant "FIELDLENGTH(16)" }; type record NcellReport { uint6_t rxlev, uint5_t bcch_freq, uint6_t bsic } with { variant ""}; type record of NcellReport NcellReports; /* 9.1.18 */ type record ImmediateAssignment { DedicatedModeOrTbf ded_or_tbf, PageMode page_mode, ChannelDescription chan_desc optional, PacketChannelDescription pkt_chan_desc optional, RequestReference req_ref, TimingAdvance timing_advance, MobileAllocation mobile_allocation, /* TODO: starting time TLV */ IaRestOctets rest_octets } with { variant (chan_desc) "PRESENCE(ded_or_tbf.tbf = false)" variant (pkt_chan_desc) "PRESENCE(ded_or_tbf.tbf = true)" }; /* 9.1.20 */ type record ReqRefWaitInd { RequestReference req_ref, WaitIndication wait_ind } with { variant "" }; type record length(4) of ReqRefWaitInd ReqRefWaitInd4; type record ImmediateAssignmentReject { FeatureIndicator feature_ind, PageMode page_mode, ReqRefWaitInd4 payload } with { variant "" }; /* 9.1.21 */ type record MeasurementReport { MeasurementResults meas_res } with { variant "" }; /* 9.1.22 */ type record PagingRequestType1 { ChannelNeeded12 chan_needed, PageMode page_mode, MobileIdentityLV mi1, MobileIdentityTLV mi2 optional, RestOctets rest_octets } with { variant "TAG(mi2, tag = 23)" }; /* 9.1.23 */ type record PagingRequestType2 { ChannelNeeded12 chan_needed, PageMode page_mode, GsmTmsi mi1, GsmTmsi mi2, MobileIdentityTLV mi3 optional, RestOctets rest_octets } with { variant "TAG(mi3, tag = 23)" }; /* 9.1.24 */ type record length(4) of GsmTmsi GsmTmsi4; type record PagingRequestType3 { ChannelNeeded12 chan_needed, PageMode page_mode, GsmTmsi4 mi, RestOctets rest_octets } with { variant "" }; type union RrUnion { /* SystemInformationType1 si1, SystemInformationType2 si2, SystemInformationType2bis si2bis, SystemInformationType2ter si2ter, SystemInformationType3 si3, SystemInformationType4 si4, SystemInformationType5 si5, SystemInformationType5bis si5bis, SystemInformationType5ter si5ter, SystemInformationType6 si6, */ ImmediateAssignment imm_ass, ImmediateAssignmentReject imm_ass_rej, PagingRequestType1 pag_req_1, PagingRequestType2 pag_req_2, PagingRequestType3 pag_req_3, octetstring other } with { variant "" }; /* Special RR Message on BCCH / CCCH Dowlink */ type record GsmRrMessage { RrHeader header, RrUnion 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; 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; */ imm_ass, header.message_type = IMMEDIATE_ASSIGNMENT; imm_ass_rej, header.message_type = IMMEDIATE_ASSIGNMENT_REJECT; pag_req_1, header.message_type = PAGING_REQUEST_TYPE_1; pag_req_2, header.message_type = PAGING_REQUEST_TYPE_2; pag_req_3, header.message_type = PAGING_REQUEST_TYPE_3; other, OTHERWISE; )" /* Total message length: 184 = 23 * 8. Pad spare bits with '2B'O. */ variant "PADDING(184), PADDING_PATTERN('00101011'B)" }; external function enc_GsmRrMessage(in GsmRrMessage msg) return octetstring with { extension "prototype(convert) encode(RAW)" }; external function dec_GsmRrMessage(in octetstring stream) return GsmRrMessage with { extension "prototype(convert) decode(RAW)" }; /* Normal L3 Message on Dedicated Channel */ /* 9.1.25 Paging Response */ type record PagingResponse { uint4_t spare_half_octet, CipheringKeySeqNr cksn, MsClassmark2LV cm2, MobileIdentityLV mi, uint8_t addl_upd_par optional } with { variant "" }; type union RrL3Union { PagingResponse paging_response, MeasurementReport meas_rep, octetstring other }; type record GsmRrL3Message { RrL3Header header, RrL3Union payload } with { variant (payload) "CROSSTAG( paging_response, header.message_type = PAGING_RESPONSE; meas_rep, header.message_type = MEASUREMENT_REPORT; other, OTHERWISE; )" } external function enc_GsmRrL3Message(in GsmRrL3Message msg) return octetstring with { extension "prototype(convert) encode(RAW)" }; external function dec_GsmRrL3Message(in octetstring stream) return GsmRrL3Message with { extension "prototype(convert) decode(RAW)" }; template PacketDlAssign tr_PacketDlAssign(template GprsTlli tlli) := { tlli := tlli, group1_present := ?, group1 := *, ta_index_present := ?, ta_index := *, tbf_starting_time_present := ?, tbf_starting_time := *, p0_present := ?, p0 := *, pr_mode := * }; template IaRestOctets tr_IaRestOctets_DLAss(template PacketDlAssign dl_ass) := { presence := '11'B, /* HH */ ll := omit, lh := omit, hl := omit, hh := { pa_disc := '0'B, /* Packet Assignment (0) */ pa := { uldl := { ass_disc := '1'B, /* Downlink Assignment (1) */ ass := { dl := dl_ass } } } } }; template PacketUlAssign tr_PacketUlDynAssign(template uint5_t tfi := ?, template BIT1 polling := ?, template uint3_t usf := ?, template BIT1 usf_granularity := ?, template ChCodingCommand cs := ?) := { presence := '1'B, /* Dynamic Block Allocation */ dynamic := { tfi_assignment := tfi, polling := polling, spare := '0'B, /* Dynamic Block Allocation (mandatory after Rel-4) */ usf := usf, usf_granularity := usf_granularity, p0_present := ?, p0 := *, pr_mode := *, ch_coding_cmd := cs, tlli_block_chan_coding := ?, alpha_present := ?, alpha := *, gamma := ?, /* TODO: add to parameters */ ta_index_present := ?, ta_index := *, tbf_starting_time_present := ?, tbf_starting_time := * }, single := omit }; template PacketUlAssign tr_PacketUlSglAssign := { presence := '0'B, /* Single Block Allocation */ dynamic := omit, single := { alpha_present := ?, alpha := *, gamma := ?, padding := '01'B, tbf_starting_time := ? } }; template IaRestOctets tr_IaRestOctets_ULAss(template PacketUlAssign ul_ass) := { presence := '11'B, /* HH */ ll := omit, lh := omit, hl := omit, hh := { pa_disc := '0'B, /* Packet Assignment (0) */ pa := { uldl := { ass_disc := '0'B, /* Uplink Assignment (0) */ ass := { ul := ul_ass } } } } }; template (value) GsmRrMessage ts_IMM_ASS(uint8_t ra, GsmFrameNumber fn, TimingAdvance ta, ChannelDescription ch_desc, MobileAllocation ma) := { header := t_RrHeader(IMMEDIATE_ASSIGNMENT, 0), payload := { imm_ass := { ded_or_tbf := { spare := '0'B, tma := false, downlink := false, tbf := false }, page_mode := PAGE_MODE_NORMAL, chan_desc := ch_desc, pkt_chan_desc := omit, req_ref := f_compute_ReqRef(ra, fn), timing_advance := ta, mobile_allocation := ma, rest_octets := { presence := '00'B, /* LL */ ll := { /* Compressed INTER RAT HO INFO: shall not be used (L) * TODO: use variant "CSN.1 L/H" to avoid confusion. */ compressed_irat_ho_info_ind := '1'B }, lh := omit, hl := omit, hh := omit } } } }; template GsmRrMessage tr_IMM_ASS(template uint8_t ra := ?, template GsmFrameNumber fn := ?, template TimingAdvance ta := ?, template ChannelDescription ch_desc := ?, template MobileAllocation ma := ?) := { header := t_RrHeader(IMMEDIATE_ASSIGNMENT, ?), payload := { imm_ass := { ded_or_tbf := { spare := '0'B, tma := false, downlink := false, tbf := false }, page_mode := PAGE_MODE_NORMAL, chan_desc := ch_desc, pkt_chan_desc := omit, req_ref := tr_compute_ReqRef(ra, fn), timing_advance := ta, mobile_allocation := ma, rest_octets := ? } } }; /* TODO: implement send version of this template */ template GsmRrMessage tr_IMM_TBF_ASS(template boolean dl := ?, template uint8_t ra := ?, template GsmFrameNumber fn := ?, template TimingAdvance ta := ?, template PacketChannelDescription ch_desc := ?, template IaRestOctets rest := ?) := { header := t_RrHeader(IMMEDIATE_ASSIGNMENT, ?), payload := { imm_ass := { ded_or_tbf := { spare := ?, tma := ?, downlink := dl, tbf := true }, page_mode := ?, chan_desc := omit, pkt_chan_desc := ch_desc, req_ref := tr_compute_ReqRef(ra, fn), timing_advance := ta, mobile_allocation := ?, rest_octets := rest } } }; template (value) GsmRrL3Message ts_MEAS_REP(boolean valid, uint6_t rxl_f, uint6_t rxl_s, uint3_t rxq_f, uint3_t rxq_s, template (omit) NcellReports reps) := { header := t_RrL3Header(MEASUREMENT_REPORT), payload := { meas_rep := { meas_res := { ba_used := '0'B, dtx_used := '0'B, rxlev_full_srv_cell := rxl_f, threeg_ba_used := '0'B, meas_valid := bool2bit(not valid), rxlev_sub_srv_cell := rxl_s, si23_ba_used := '0'B, rxqual_full_srv_cell := rxq_f, rxqual_sub_srv_cell := rxq_s, no_ncell_m := 0, ncell_reports := reps } } } }; } with { encode "RAW" ; variant "FIELDORDER(msb)" }