/* Data Types / Encoding / Decoding for OsmocomBB L1CTL interface */ /* (C) 2017 by Harald Welte , derived from l1ctl_proto.h * which is (C) 2010 by Harald Welte + Holger Hans Peter Freyther * 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 L1CTL_Types { import from General_Types all; import from GSM_Types all; import from GSM_RR_Types all; import from Osmocom_Types all; type uint32_t uint32_le with { variant "BYTEORDER(first)" }; type enumerated L1ctlMsgType { L1CTL_NONE, L1CTL_FBSB_REQ, L1CTL_FBSB_CONF, L1CTL_DATA_IND, L1CTL_RACH_REQ, L1CTL_DM_EST_REQ, L1CTL_DATA_REQ, L1CTL_RESET_IND, L1CTL_PM_REQ, /* power measurement */ L1CTL_PM_CONF, /* power measurement */ L1CTL_ECHO_REQ, L1CTL_ECHO_CONF, L1CTL_RACH_CONF, L1CTL_RESET_REQ, L1CTL_RESET_CONF, L1CTL_DATA_CONF, L1CTL_CCCH_MODE_REQ, L1CTL_CCCH_MODE_CONF, L1CTL_DM_REL_REQ, L1CTL_PARAM_REQ, L1CTL_DM_FREQ_REQ, L1CTL_CRYPTO_REQ, L1CTL_SIM_REQ, L1CTL_SIM_CONF, L1CTL_TCH_MODE_REQ, L1CTL_TCH_MODE_CONF, L1CTL_NEIGH_PM_REQ, L1CTL_NEIGH_PM_IND, L1CTL_TRAFFIC_REQ, L1CTL_TRAFFIC_CONF, L1CTL_TRAFFIC_IND, L1CTL_BURST_IND, L1CTL_TBF_CFG_REQ, L1CTL_TBF_CFG_CONF, L1CTL_DATA_TBF_REQ, L1CTL_DATA_TBF_CONF, L1CTL_EXT_RACH_REQ, L1CTL_DATA_ABS_REQ /*!< FIXME: no such message in OsmocomBB */ } with { variant "FIELDLENGTH(8)" }; type enumerated L1ctlCcchMode { CCCH_MODE_NONE (0), CCCH_MODE_NON_COMBINED, CCCH_MODE_COMBINED, CCCH_MODE_COMBINED_CBCH } with { variant "FIELDLENGTH(8)" }; type enumerated L1ctlNeighMode { NEIGH_MODE_NONE (0), NEIGH_MODE_PM, NEIGH_MODE_SB } with { variant "FIELDLENGTH(8)" }; type enumerated L1ctlGprsCs { L1CTL_CS1 (1), L1CTL_CS2, L1CTL_CS3, L1CTL_CS4, L1CTL_MCS1, L1CTL_MCS2, L1CTL_MCS3, L1CTL_MCS4, L1CTL_MCS5, L1CTL_MCS6, L1CTL_MCS7, L1CTL_MCS8, L1CTL_MCS9 } with { variant "FIELDLENGTH(8)" }; type enumerated L1ctlResetType { L1CTL_RES_T_BOOT (0), L1CTL_RES_T_FULL, L1CTL_RES_T_SCHED } with { variant "FIELDLENGTH(8)" }; type record L1ctlHdrFlags { BIT7 padding, boolean f_done } with { variant "" }; type record L1ctlHeader { L1ctlMsgType msg_type, L1ctlHdrFlags flags, OCT2 padding } with { variant "" }; template L1ctlHeader tr_L1ctlHeader(template (present) L1ctlMsgType msg_type) := { msg_type := msg_type, flags := ?, padding := ? }; template (value) L1ctlHeader ts_L1ctlHeader(template (value) L1ctlMsgType msg_type) := { msg_type := msg_type, flags := { padding := '0000000'B, f_done := false }, padding := '0000'O }; type record L1ctlDlInfo { RslChannelNr chan_nr, RslLinkId link_id, GsmBandArfcn arfcn, uint32_t frame_nr, GsmRxLev rx_level, uint8_t snr, uint8_t num_biterr, uint8_t fire_crc } with { variant "" }; type record L1ctlFbsbConf { int16_t initial_freq_err, uint8_t result, uint8_t bsic } with { variant "" }; type record L1ctlCcchModeConf { L1ctlCcchMode ccch_mode, OCT3 padding } with { variant "" }; /* gsm48_chan_mode */ type enumerated L1ctlTchMode { L1CTL_CHAN_MODE_SIGN ('00000000'B), /* Signalling */ L1CTL_CHAN_MODE_SPEECH_V1 ('00000001'B), /* FR or HR codec */ L1CTL_CHAN_MODE_SPEECH_V2 ('00100001'B), /* EFR codec */ L1CTL_CHAN_MODE_SPEECH_V3 ('01000001'B) /* AMR codec */ /* Other modes are not supported for now */ } with { variant "FIELDLENGTH(8)" }; type enumerated L1ctlLoopMode { L1CTL_LOOP_MODE_OPEN ('00000000'B), L1CTL_LOOP_MODE_A ('00000001'B), L1CTL_LOOP_MODE_B ('00000010'B), L1CTL_LOOP_MODE_C ('00000011'B), L1CTL_LOOP_MODE_D ('00000100'B), L1CTL_LOOP_MODE_E ('00000101'B), L1CTL_LOOP_MODE_F ('00000110'B), L1CTL_LOOP_MODE_I ('00000111'B) } with { variant "FIELDLENGTH(8)" }; type record L1ctlAudioMode { BIT4 padding, boolean tx_microphone, boolean tx_traffic_req, boolean rx_speaker, boolean rx_traffic_ind } with { variant "" }; template (value) L1ctlAudioMode t_L1CTL_AudioModeNone := { '0000'B, false, false, false, false }; /* Traffic forwarding mode (see TRAFFIC.{req,cnf,ind} messages) */ template (value) L1ctlAudioMode t_L1CTL_AudioModeFwd modifies t_L1CTL_AudioModeNone := { tx_traffic_req := true, rx_traffic_ind := true }; type record L1ctlTchModeConf { L1ctlTchMode tch_mode, L1ctlAudioMode audio_mode, OCT2 padding } with { variant "" }; type record L1ctlDataInd { octetstring payload } with { variant (payload) "BYTEORDER(first)" }; type union L1ctlDlPayload { L1ctlFbsbConf fbsb_conf, L1ctlCcchModeConf ccch_mode_conf, L1ctlTchModeConf tch_mode_conf, L1ctlDataInd data_ind, L1ctlTrafficReq traffic_ind, L1ctlTbfCfgReq tbf_cfg_conf, octetstring other } with { variant (other) "BYTEORDER(first)" }; type record L1ctlDlMessage { L1ctlHeader header, L1ctlDlInfo dl_info optional, L1ctlDlPayload payload optional } with { variant (dl_info) "PRESENCE(header.msg_type = L1CTL_FBSB_CONF, header.msg_type = L1CTL_RACH_CONF, header.msg_type = L1CTL_DATA_IND, header.msg_type = L1CTL_DATA_CONF, header.msg_type = L1CTL_TRAFFIC_IND, header.msg_type = L1CTL_TRAFFIC_CONF)" variant (payload) "CROSSTAG(fbsb_conf, header.msg_type = L1CTL_FBSB_CONF; ccch_mode_conf, header.msg_type = L1CTL_CCCH_MODE_CONF; tch_mode_conf, header.msg_type = L1CTL_TCH_MODE_CONF; data_ind, header.msg_type = L1CTL_DATA_IND; traffic_ind, header.msg_type = L1CTL_TRAFFIC_IND; tbf_cfg_conf, header.msg_type = L1CTL_TBF_CFG_CONF; other, OTHERWISE; )" }; external function enc_L1ctlDlMessage(in L1ctlDlMessage msg) return octetstring with { extension "prototype(convert) encode(RAW)" }; external function dec_L1ctlDlMessage(in octetstring stream) return L1ctlDlMessage with { extension "prototype(convert) decode(RAW)" }; type record L1ctlUlInfo { RslChannelNr chan_nr, RslLinkId link_id, OCT2 padding } with { variant "" }; type record L1ctlUlTbfInfo { uint8_t tbf_nr, L1ctlGprsCs cs, OCT2 padding } with { variant "" }; type record L1ctlUlAbsInfo { uint8_t tbf_nr, L1ctlGprsCs cs, uint8_t ts_nr, OCT1 padding, uint32_le fn, GsmBandArfcn arfcn, OCT2 padding2 } with { variant "" }; type record L1ctlFbsbFlags { BIT5 padding, boolean sb, boolean fb1, boolean fb0 } with { variant "FIELDORDER(msb)" }; template (value) L1ctlFbsbFlags t_L1CTL_FBSB_F_ALL := { padding := '00000'B, sb := true, fb1 := true, fb0 := true }; type record L1ctlFbsbReq { GsmBandArfcn arfcn, uint16_t timeout_tdma_frames, uint16_t freq_err_thresh1, uint16_t freq_err_thresh2, uint8_t num_freqerr_avg, L1ctlFbsbFlags flags, uint8_t sync_info_idx, L1ctlCcchMode ccch_mode, GsmRxLev rxlev_exp } with { variant "" }; type record L1ctlCcchModeReq { L1ctlCcchMode ccch_mode, OCT3 padding } with { variant "" }; type record L1ctlTchModeReq { L1ctlTchMode tch_mode, L1ctlAudioMode audio_mode, L1ctlLoopMode loop_mode, OCT1 padding } with { variant "" }; type record L1ctlRachReq { uint8_t ra, uint8_t combined, uint16_t offset } with { variant "" }; type enumerated L1ctlRachSynchSeq { RACH_SYNCH_SEQ_TS0 (0), RACH_SYNCH_SEQ_TS1, RACH_SYNCH_SEQ_TS2 } with { variant "FIELDLENGTH(8)" }; type record L1ctlExtRachReq { uint16_t ra11, L1ctlRachSynchSeq synch_seq, uint8_t combined, uint16_t offset } with { variant "" }; type record L1ctlParReq { int8_t ta, uint8_t tx_power, OCT2 padding } with { variant "" }; type record L1ctlDataReq { SacchL1Header l1header optional, octetstring l2_payload } with { variant "" }; type record L1ctlH0 { uint8_t h, GsmBandArfcn arfcn, octetstring padding length(130) } with { variant "" }; type record length(0..64) of GsmBandArfcn L1ctlMA; type record L1ctlH1 { uint8_t h, uint8_t hsn, uint8_t maio, uint8_t n, OCT1 spare, L1ctlMA ma, octetstring padding } with { variant (n) "LENGTHTO(ma)" variant (n) "UNIT(elements)" /* See https://bugs.eclipse.org/bugs/show_bug.cgi?id=562849. * TL;DR The reference point of the PADDING attribute is the beginning * of the message, not the beginning of the type/field it's applied on. * Therefore we cannot use it here, and have to add padding manually. * variant (ma) "PADDING(128)" */ }; type union L1ctlH0H1 { L1ctlH0 h0, L1ctlH1 h1 } with { variant "TAG(h0, h = 0; h1, h = 1)" }; type record L1ctlDmEstReq { GsmTsc tsc, L1ctlH0H1 h0h1, L1ctlTchMode tch_mode, L1ctlAudioMode audio_mode } with { variant "" }; type record L1ctlReset { L1ctlResetType reset_type, OCT3 padding } with { variant "" }; type record L1CtlCryptoReq { uint8_t algo, uint8_t key_len, octetstring key } with { variant (key_len) "LENGTHTO(key)" }; type record L1ctlTrafficReq { octetstring data } with { variant (data) "BYTEORDER(first)" } type record length(8) of uint8_t TfiUsfArr; type record L1ctlTbfCfgReq { uint8_t tbf_nr, boolean is_uplink, OCT2 padding, TfiUsfArr tfi_usf } with { variant (is_uplink) "FIELDLENGTH(8)" }; type union L1ctlUlPayload { L1ctlFbsbReq fbsb_req, L1ctlCcchModeReq ccch_mode_req, L1ctlTchModeReq tch_mode_req, L1ctlRachReq rach_req, L1ctlExtRachReq ext_rach_req, L1ctlParReq par_req, L1ctlDmEstReq dm_est_req, L1ctlReset reset_req, //L1ctlNeighPmReq neigh_pm_req, L1CtlCryptoReq crypto_req, L1ctlTrafficReq traffic_req, L1ctlTbfCfgReq tbf_cfg_req, L1ctlDataReq data_req, octetstring other } with { variant (other) "BYTEORDER(first)" }; type record L1ctlUlMessage { L1ctlHeader header, L1ctlUlInfo ul_info optional, L1ctlUlTbfInfo ul_info_tbf optional, L1ctlUlAbsInfo ul_info_abs optional, L1ctlUlPayload payload } with { variant (ul_info) "PRESENCE(header.msg_type = L1CTL_RACH_REQ, header.msg_type = L1CTL_EXT_RACH_REQ, header.msg_type = L1CTL_PARAM_REQ, header.msg_type = L1CTL_CRYPTO_REQ, header.msg_type = L1CTL_DATA_REQ, header.msg_type = L1CTL_DM_EST_REQ, header.msg_type = L1CTL_DM_FREQ_REQ, header.msg_type = L1CTL_DM_REL_REQ, header.msg_type = L1CTL_TRAFFIC_REQ)" variant (ul_info_tbf) "PRESENCE(header.msg_type = L1CTL_DATA_TBF_REQ)" variant (ul_info_abs) "PRESENCE(header.msg_type = L1CTL_DATA_ABS_REQ)" variant (payload) "CROSSTAG(fbsb_req, header.msg_type = L1CTL_FBSB_REQ; ccch_mode_req, header.msg_type = L1CTL_CCCH_MODE_REQ; tch_mode_req, header.msg_type = L1CTL_TCH_MODE_REQ; rach_req, header.msg_type = L1CTL_RACH_REQ; ext_rach_req, header.msg_type = L1CTL_EXT_RACH_REQ; par_req, header.msg_type = L1CTL_PARAM_REQ; dm_est_req, header.msg_type = L1CTL_DM_EST_REQ; reset_req, header.msg_type = L1CTL_RESET_REQ; crypto_req, header.msg_type = L1CTL_CRYPTO_REQ; traffic_req, header.msg_type = L1CTL_TRAFFIC_REQ; tbf_cfg_req, header.msg_type = L1CTL_TBF_CFG_REQ; data_req, header.msg_type = L1CTL_DATA_REQ; other, OTHERWISE; )" }; external function enc_L1ctlUlMessage(in L1ctlUlMessage msg) return octetstring with { extension "prototype(convert) encode(RAW)" }; external function dec_L1ctlUlMessage(in octetstring stream) return L1ctlUlMessage with { extension "prototype(convert) decode(RAW)" }; type record L1ctlUlMessageLV { uint16_t len, L1ctlUlMessage msg } with { variant (len) "LENGTHTO(msg)" }; external function enc_L1ctlUlMessageLV(in L1ctlUlMessageLV msg) return octetstring with { extension "prototype(convert) encode(RAW)" }; external function dec_L1ctlUlMessageLV(in octetstring stream) return L1ctlUlMessageLV with { extension "prototype(convert) decode(RAW)" }; type record L1ctlDlMessageLV { uint16_t len, L1ctlDlMessage msg } with { variant (len) "LENGTHTO(msg)" }; external function enc_L1ctlDlMessageLV(in L1ctlDlMessageLV msg) return octetstring with { extension "prototype(convert) encode(RAW)" }; external function dec_L1ctlDlMessageLV(in octetstring stream) return L1ctlDlMessageLV with { extension "prototype(convert) decode(RAW)" }; /* for generating RESET_REQ */ template (value) L1ctlUlMessage t_L1ctlResetReq(template (value) L1ctlResetType rst_type) := { header := ts_L1ctlHeader(L1CTL_RESET_REQ), ul_info := omit, ul_info_tbf := omit, ul_info_abs := omit, payload := { reset_req := { reset_type := rst_type, padding := '000000'O } } }; /* for generating FBSB_REQ */ template (value) L1ctlUlMessage ts_L1CTL_FBSB_REQ(template (value) GsmBandArfcn arfcn, template (value) L1ctlFbsbFlags flags, template (value) uint8_t sync_info_idx, template (value) L1ctlCcchMode ccch_mode, template (value) GsmRxLev rxlev_exp) := { header := ts_L1ctlHeader(L1CTL_FBSB_REQ), ul_info := omit, ul_info_tbf := omit, ul_info_abs := omit, payload := { fbsb_req := { arfcn := arfcn, timeout_tdma_frames := 250, /* about 1s */ freq_err_thresh1 := 10000, freq_err_thresh2 := 800, num_freqerr_avg := 3, flags := flags, sync_info_idx := sync_info_idx, ccch_mode := ccch_mode, rxlev_exp := rxlev_exp } } }; /* for matching against incoming FBSB_CONF */ template L1ctlDlMessage tr_L1CTL_FBSB_CONF(template (present) uint8_t result) := { header := tr_L1ctlHeader(L1CTL_FBSB_CONF), dl_info := ?, payload := { fbsb_conf := { initial_freq_err := ?, result := result, bsic := ? } } }; template (value) L1ctlUlMessage ts_L1CTL_CCCH_MODE_REQ(template (value) L1ctlCcchMode ccch_mode) := { header := ts_L1ctlHeader(L1CTL_CCCH_MODE_REQ), ul_info := omit, ul_info_tbf := omit, ul_info_abs := omit, payload := { ccch_mode_req := { ccch_mode := ccch_mode, padding := '000000'O } } }; template (value) L1ctlUlMessage ts_L1CTL_TCH_MODE_REQ(template (value) L1ctlTchMode tch_mode := L1CTL_CHAN_MODE_SIGN, template (value) L1ctlAudioMode audio_mode := t_L1CTL_AudioModeFwd, template (value) L1ctlLoopMode loop_mode := L1CTL_LOOP_MODE_OPEN) := { header := ts_L1ctlHeader(L1CTL_TCH_MODE_REQ), ul_info := omit, ul_info_tbf := omit, ul_info_abs := omit, payload := { tch_mode_req := { tch_mode := tch_mode, audio_mode := audio_mode, loop_mode := loop_mode, padding := '00'O } } }; template L1ctlDlMessage tr_L1CTL_MsgType(template (present) L1ctlMsgType msg_type) := { header := tr_L1ctlHeader(msg_type), dl_info := *, payload := * } template L1ctlDlMessage tr_L1CTL_CCCH_MODE_CONF := tr_L1CTL_MsgType(L1CTL_CCCH_MODE_CONF); template (value) L1ctlUlMessage ts_L1CTL_RACH_REQ(template (value) uint8_t ra, template (value) uint8_t combined, template (value) uint16_t offset, template (value) RslChannelNr chan_nr := ts_RslChanNr_RACH(0), template (value) RslLinkId link_id := ts_RslLinkID_DCCH(0)) := { header := ts_L1ctlHeader(L1CTL_RACH_REQ), ul_info := { chan_nr := chan_nr, link_id := link_id, padding := '0000'O }, ul_info_tbf := omit, ul_info_abs := omit, payload := { rach_req := { ra := ra, combined := combined, offset := offset } } } template (value) L1ctlUlMessage ts_L1CTL_EXT_RACH_REQ(template (value) uint16_t ra11, template (value) L1ctlRachSynchSeq seq, template (value) uint8_t combined, template (value) uint16_t offset) := { header := ts_L1ctlHeader(L1CTL_EXT_RACH_REQ), ul_info := { /* FIXME: both RSL chan_nr and link_id should be configurable */ chan_nr := t_RslChanNr_RACH(0), link_id := ts_RslLinkID_DCCH(0), padding := '0000'O }, ul_info_tbf := omit, ul_info_abs := omit, payload := { ext_rach_req := { ra11 := ra11, synch_seq := seq, combined := combined, offset := offset } } } template (value) L1ctlUlMessage ts_L1CTL_PAR_REQ(template (value) uint8_t ta, template (value) uint8_t tx_power) := { header := ts_L1ctlHeader(L1CTL_PARAM_REQ), ul_info := { chan_nr := t_RslChanNr_RACH(0), link_id := ts_RslLinkID_DCCH(0), padding := '0000'O }, ul_info_tbf := omit, ul_info_abs := omit, payload := { par_req := { ta := ta, tx_power := tx_power, padding := '0000'O } } } /* Base template to be inherited by ts_L1CTL_DM_EST_REQ_H0 and ts_L1CTL_DM_EST_REQ_H1 */ private template (value) L1ctlUlMessage ts_L1CTL_DM_EST_REQ(template (value) RslChannelNr chan_nr, template (value) GsmTsc tsc) := { header := ts_L1ctlHeader(L1CTL_DM_EST_REQ), ul_info := { chan_nr := chan_nr, link_id := ts_RslLinkID_DCCH(0), padding := '0000'O }, ul_info_tbf := omit, ul_info_abs := omit, payload := { dm_est_req := { tsc := tsc, tch_mode := L1CTL_CHAN_MODE_SIGN, audio_mode := t_L1CTL_AudioModeFwd } } } template (value) L1ctlUlMessage ts_L1CTL_DM_EST_REQ_H0(template (value) RslChannelNr chan_nr, template (value) GsmTsc tsc, template (value) GsmArfcn arfcn) modifies ts_L1CTL_DM_EST_REQ := { payload := { dm_est_req := { h0h1 := { h0 := { h := 0, arfcn := ts_GsmBandArfcn(arfcn), padding := f_pad_oct(''O, 130, '00'O) } } } } } template (value) L1ctlUlMessage ts_L1CTL_DM_EST_REQ_H1(template (value) RslChannelNr chan_nr, template (value) GsmTsc tsc, template (value) uint6_t hsn, template (value) uint6_t maio, template (value) L1ctlMA ma) modifies ts_L1CTL_DM_EST_REQ := { payload := { dm_est_req := { h0h1 := { h1 := { h := 1, hsn := hsn, maio := maio, n := sizeof(ma), spare := '00'O, ma := ma, /* See https://bugs.eclipse.org/bugs/show_bug.cgi?id=562849 */ padding := f_pad_oct(''O, (64 - sizeof(ma)) * 2, '00'O) } } } } } template (value) L1ctlUlMessage ts_L1CTL_DM_REL_REQ(template (value) RslChannelNr chan_nr) := { header := ts_L1ctlHeader(L1CTL_DM_REL_REQ), ul_info := { chan_nr := chan_nr, link_id := ts_RslLinkID_DCCH(0), padding := '0000'O }, ul_info_tbf := omit, ul_info_abs := omit, payload := { other := ''O } } template (value) L1ctlUlMessage ts_L1CTL_DATA_REQ(template (value) RslChannelNr chan_nr, template (value) RslLinkId link_id, octetstring l2_data) := { header := ts_L1ctlHeader(L1CTL_DATA_REQ), ul_info := { chan_nr := chan_nr, link_id := link_id, padding := '0000'O }, ul_info_tbf := omit, ul_info_abs := omit, payload := { data_req := { l1header := omit, l2_payload := l2_data } } } template (value) L1ctlUlMessage ts_L1CTL_DATA_REQ_SACCH(template (value) RslChannelNr chan_nr, template (value) RslLinkId link_id, template (value) SacchL1Header l1h, octetstring l2_data) := { header := ts_L1ctlHeader(L1CTL_DATA_REQ), ul_info := { chan_nr := chan_nr, link_id := link_id, padding := '0000'O }, ul_info_tbf := omit, ul_info_abs := omit, payload := { data_req := { l1header := l1h, l2_payload := l2_data } } } template (value) L1ctlUlMessage ts_L1CTL_TRAFFIC_REQ(template (value) RslChannelNr chan_nr, template (value) RslLinkId link_id, octetstring frame) := { header := ts_L1ctlHeader(L1CTL_TRAFFIC_REQ), ul_info := { chan_nr := chan_nr, link_id := link_id, padding := '0000'O }, ul_info_tbf := omit, ul_info_abs := omit, payload := { traffic_req := { data := frame } } }; template (value) L1ctlUlMessage ts_L1CTL_TBF_CFG_REQ(template (value) boolean is_uplink, template (value) TfiUsfArr tfi_usf) := { header := ts_L1ctlHeader(L1CTL_TBF_CFG_REQ), ul_info := omit, ul_info_tbf := omit, ul_info_abs := omit, payload := { tbf_cfg_req := { tbf_nr := 0, is_uplink := is_uplink, padding := '0000'O, tfi_usf := tfi_usf } } }; template L1ctlDlMessage tr_L1CTL_TBF_CFG_CONF(template (present) boolean is_uplink) := { header := tr_L1ctlHeader(L1CTL_TBF_CFG_CONF), dl_info := omit, payload := { tbf_cfg_conf := { tbf_nr := 0, is_uplink := is_uplink, padding := ?, tfi_usf := ? } } }; template (value) L1ctlUlMessage ts_L1CTL_DATA_TBF_REQ(octetstring l2_data, template (value) L1ctlGprsCs cs := L1CTL_CS1, template (value) uint8_t tbf_nr := 0) := { header := ts_L1ctlHeader(L1CTL_DATA_TBF_REQ), ul_info := omit, ul_info_tbf := { tbf_nr := tbf_nr, cs := cs, padding := '0000'O }, ul_info_abs := omit, payload := { other := l2_data } } template (value) L1ctlUlMessage ts_L1CTL_DATA_ABS_REQ(octetstring l2_data, template (value) GsmBandArfcn arfcn, template (value) uint8_t ts, template (value) GsmFrameNumber fn, template (value) L1ctlGprsCs cs := L1CTL_CS1, template (value) uint8_t tbf_nr := 0) := { header := ts_L1ctlHeader(L1CTL_DATA_ABS_REQ), ul_info := omit, ul_info_tbf := omit, ul_info_abs := { tbf_nr := tbf_nr, cs := cs, ts_nr := ts, padding := '00'O, fn := fn, arfcn := arfcn, padding2 := '0000'O }, payload := { other := l2_data } } /* for matching against incoming RACH_CONF */ template L1ctlDlMessage tr_L1CTL_RACH_CONF := { header := tr_L1ctlHeader(L1CTL_RACH_CONF), dl_info := ?, payload := * }; /* for matching against incoming DATA_IND */ template L1ctlDlMessage tr_L1CTL_DATA_IND(template (present) RslChannelNr chan_nr, template (present) RslLinkId link_id := ?, template (present) octetstring l2_data := ?, template (present) uint8_t num_biterr := 0, template (present) uint8_t fire_crc := 0) := { header := tr_L1ctlHeader(L1CTL_DATA_IND), dl_info := { chan_nr := chan_nr, link_id := link_id, arfcn := ?, frame_nr := ?, rx_level := ?, snr := ?, num_biterr := num_biterr, fire_crc := fire_crc }, payload := { data_ind := { payload := l2_data } } }; /* for matching against incoming TRAFFIC_IND */ template L1ctlDlMessage tr_L1CTL_TRAFFIC_IND(template (present) RslChannelNr chan_nr, template (present) RslLinkId link_id := ?, template (present) octetstring frame := ?, template (present) uint8_t num_biterr := ?, template (present) uint8_t fire_crc := ?) := { header := tr_L1ctlHeader(L1CTL_TRAFFIC_IND), dl_info := { chan_nr := chan_nr, link_id := link_id, arfcn := ?, frame_nr := ?, rx_level := ?, snr := ?, num_biterr := num_biterr, fire_crc := fire_crc }, payload := { traffic_ind := { data := frame } } }; template (value) L1ctlUlMessage ts_L1CTL_CRYPTO_REQ(template (value) RslChannelNr chan_nr, template (value) uint8_t algo, template (value) octetstring key) := { header := ts_L1ctlHeader(L1CTL_CRYPTO_REQ), ul_info := { chan_nr := chan_nr, link_id := ts_RslLinkID_DCCH(0), padding := '0000'O }, ul_info_tbf := omit, ul_info_abs := omit, payload := { crypto_req := { algo := algo, key_len := 0, /* overwritten */ key := key } } }; const octetstring c_DummyUI := '0303012B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B'O; /* We use "BYTEORDER(last)" so we get little-endian integers. Unfortuantely, this also switches the byte ordering in octet strings, so we need to explicitly annotate them :/ */ } with { encode "RAW" };