#include "RLCMAC_Types.hh" #include "GSM_Types.hh" /* Decoding of TS 44.060 GPRS RLC/MAC blocks, portions requiring manual functions * beyond what TITAN RAW coder can handle internally. * * (C) 2017 by Harald Welte */ namespace RLCMAC__Types { OCTETSTRING enc__RlcmacDlDataBlock(const RlcmacDlDataBlock& si) { RlcmacDlDataBlock in = si; OCTETSTRING ret_val; TTCN_Buffer ttcn_buffer; int i; /* Fix 'e' bit of initial header based on following blocks */ if (!in.blocks().is_bound() || (in.blocks().size_of() == 1 && !in.blocks()[0].hdr().is_bound())) in.mac__hdr().hdr__ext().e() = true; else in.mac__hdr().hdr__ext().e() = false; /* use automatic/generated decoder for header */ in.mac__hdr().encode(DlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW); /* Add LI octets, if any */ if (in.blocks().is_bound() && (in.blocks().size_of() != 1 || in.blocks()[0].hdr().is_bound())) { /* first write LI octets */ for (i = 0; i < in.blocks().size_of(); i++) { /* fix the 'E' bit in case it is not clear */ if (i < in.blocks().size_of()-1) in.blocks()[i].hdr().e() = false; else in.blocks()[i].hdr().e() = true; in.blocks()[i].hdr().encode(LlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW); } } if (in.blocks().is_bound()) { for (i = 0; i < in.blocks().size_of(); i++) { if (!in.blocks()[i].is_bound()) continue; ttcn_buffer.put_string(in.blocks()[i].payload()); } } ttcn_buffer.get_string(ret_val); return ret_val; } RlcmacDlDataBlock dec__RlcmacDlDataBlock(const OCTETSTRING& stream) { RlcmacDlDataBlock ret_val; TTCN_Buffer ttcn_buffer(stream); int num_llc_blocks = 0; /* use automatic/generated decoder for header */ ret_val.mac__hdr().decode(DlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW); /* optional extension octets, containing LI+M+E of Llc blocks */ if (ret_val.mac__hdr().hdr__ext().e() == false) { /* extension octet follows, i.e. optional Llc length octets */ while (1) { /* decode one more extension octet with LlcBlocHdr inside */ LlcBlock lb; lb.hdr().decode(LlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW); ret_val.blocks()[num_llc_blocks++] = lb; /* if E == '1'B, we can proceed further */ if (lb.hdr().e() == true) break; } } /* RLC blocks at end */ if (ret_val.mac__hdr().hdr__ext().e() == true) { LlcBlock lb; unsigned int length = ttcn_buffer.get_read_len(); /* LI not present: The Upper Layer PDU that starts with the current RLC data block either * fills the current RLC data block precisely or continues in the following in-sequence RLC * data block */ lb.payload() = OCTETSTRING(length, ttcn_buffer.get_read_data()); ttcn_buffer.increase_pos(length); ret_val.blocks()[0] = lb; } else { if (ret_val.blocks().is_bound()) { for (int i = 0; i < ret_val.blocks().size_of(); i++) { unsigned int length = ret_val.blocks()[i].hdr().length__ind(); if (length > ttcn_buffer.get_read_len()) length = ttcn_buffer.get_read_len(); ret_val.blocks()[i].payload() = OCTETSTRING(length, ttcn_buffer.get_read_data()); ttcn_buffer.increase_pos(length); } } } return ret_val; } OCTETSTRING enc__RlcmacUlDataBlock(const RlcmacUlDataBlock& si) { RlcmacUlDataBlock in = si; OCTETSTRING ret_val; TTCN_Buffer ttcn_buffer; int i; /* Fix 'e' bit of initial header based on following blocks */ if (!in.blocks().is_bound() || (in.blocks().size_of() == 1 && !in.blocks()[0].hdr().is_bound())) in.mac__hdr().e() = true; else in.mac__hdr().e() = false; /* Fix other presence indications */ in.mac__hdr().tlli__ind() = in.tlli().is_bound() && in.tlli() != OMIT_VALUE; in.mac__hdr().pfi__ind() = in.pfi().is_bound() && in.pfi() != OMIT_VALUE; /* use automatic/generated decoder for header */ in.mac__hdr().encode(UlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW); /* Add LI octets, if any */ if (in.blocks().is_bound() && (in.blocks().size_of() != 1 || in.blocks()[0].hdr().is_bound())) { /* first write LI octets */ for (i = 0; i < in.blocks().size_of(); i++) { /* fix the 'E' bit in case it is not clear */ if (i < in.blocks().size_of()-1) in.blocks()[i].hdr().e() = false; else in.blocks()[i].hdr().e() = true; in.blocks()[i].hdr().encode(LlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW); } } if (in.mac__hdr().tlli__ind()) { /* FIXME */ //in.tlli().encode(GSM__Types::GprsTlli_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW); INTEGER t = in.tlli(); unsigned int tmp = t.get_long_long_val(); ttcn_buffer.put_c(tmp >> 24); ttcn_buffer.put_c(tmp >> 16); ttcn_buffer.put_c(tmp >> 8); ttcn_buffer.put_c(tmp); } if (in.mac__hdr().pfi__ind()) { in.pfi().encode(RlcmacUlDataBlock_pfi_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW); } if (in.blocks().is_bound()) { for (i = 0; i < in.blocks().size_of(); i++) { if (!in.blocks()[i].is_bound()) continue; ttcn_buffer.put_string(in.blocks()[i].payload()); } } ttcn_buffer.get_string(ret_val); return ret_val; } RlcmacUlDataBlock dec__RlcmacUlDataBlock(const OCTETSTRING& stream) { RlcmacUlDataBlock ret_val; TTCN_Buffer ttcn_buffer(stream); int num_llc_blocks = 0; TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC); TTCN_Logger::log_event_str("==================================\n" "dec_RlcmacUlDataBlock(): Stream before decoding: "); stream.log(); TTCN_Logger::end_event(); /* use automatic/generated decoder for header */ ret_val.mac__hdr().decode(UlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW); TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC); TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): Stream after decoding hdr: "); ttcn_buffer.log(); TTCN_Logger::end_event(); TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC); TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): ret_val after decoding hdr: "); ret_val.log(); TTCN_Logger::end_event(); /* Manually decoder remainder of ttcn_buffer, containing optional header octets, * optional tlli, optional pfi and LLC Blocks */ /* optional extension octets, containing LI+M+E of Llc blocks */ if (ret_val.mac__hdr().e() == false) { /* extension octet follows, i.e. optional Llc length octets */ while (1) { /* decode one more extension octet with LlcBlocHdr inside */ LlcBlock lb; lb.hdr().decode(LlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW); ret_val.blocks()[num_llc_blocks++] = lb; TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC); TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): Stream after decoding ExtOct: "); ttcn_buffer.log(); TTCN_Logger::end_event(); TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC); TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): ret_val after decoding ExtOct: "); ret_val.log(); TTCN_Logger::end_event(); /* if E == '1'B, we can proceed further */ if (lb.hdr().e() == true) break; } } /* parse optional TLLI */ if (ret_val.mac__hdr().tlli__ind()) { /* FIXME: Why is this not working ?!? */ //ret_val.tlli().decode(GSM__Types::GprsTlli_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW); const unsigned char *cur = ttcn_buffer.get_read_data(); unsigned int tmp = cur[0] << 24 | cur[1] << 16 | cur[2] << 8 | cur[3]; INTEGER t; t.set_long_long_val(tmp); ret_val.tlli() = t; ttcn_buffer.increase_pos(4); } /* parse optional PFI */ if (ret_val.mac__hdr().pfi__ind()) { ret_val.pfi().decode(RlcmacUlDataBlock_pfi_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW); } /* RLC blocks at end */ if (ret_val.mac__hdr().e() == true) { LlcBlock lb; unsigned int length = ttcn_buffer.get_read_len(); /* LI not present: The Upper Layer PDU that starts with the current RLC data block either * fills the current RLC data block precisely or continues in the following in-sequence RLC * data block */ lb.payload() = OCTETSTRING(length, ttcn_buffer.get_read_data()); ttcn_buffer.increase_pos(length); ret_val.blocks()[0] = lb; } else { if (ret_val.blocks().is_bound()) { for (int i = 0; i < ret_val.blocks().size_of(); i++) { unsigned int length = ret_val.blocks()[i].hdr().length__ind(); if (length > ttcn_buffer.get_read_len()) length = ttcn_buffer.get_read_len(); ret_val.blocks()[i].payload() = OCTETSTRING(length, ttcn_buffer.get_read_data()); ttcn_buffer.increase_pos(length); } } } TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC); TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): Stream before return: "); ttcn_buffer.log(); TTCN_Logger::end_event(); TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC); TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): ret_val before return: "); ret_val.log(); TTCN_Logger::end_event(); return ret_val; } OCTETSTRING enc__RlcmacUlBlock(const RlcmacUlBlock& si) { if (si.ischosen(RlcmacUlBlock::ALT_data)) return enc__RlcmacUlDataBlock(si.data()); else return enc__RlcmacUlCtrlBlock(si.ctrl()); } OCTETSTRING enc__RlcmacDlBlock(const RlcmacDlBlock& si) { if (si.ischosen(RlcmacDlBlock::ALT_data)) return enc__RlcmacDlDataBlock(si.data()); else return enc__RlcmacDlCtrlBlock(si.ctrl()); } RlcmacUlBlock dec__RlcmacUlBlock(const OCTETSTRING& stream) { RlcmacUlBlock ret_val; unsigned char pt = stream[0].get_octet() >> 6; if (pt == MacPayloadType::MAC__PT__RLC__DATA) ret_val.data() = dec__RlcmacUlDataBlock(stream); else ret_val.ctrl() = dec__RlcmacUlCtrlBlock(stream); return ret_val; } RlcmacDlBlock dec__RlcmacDlBlock(const OCTETSTRING& stream) { RlcmacDlBlock ret_val; unsigned char pt = stream[0].get_octet() >> 6; if (pt == MacPayloadType::MAC__PT__RLC__DATA) ret_val.data() = dec__RlcmacDlDataBlock(stream); else ret_val.ctrl() = dec__RlcmacDlCtrlBlock(stream); return ret_val; } } // namespace