diff options
Diffstat (limited to 'library/RLCMAC_EncDec.cc')
-rw-r--r-- | library/RLCMAC_EncDec.cc | 196 |
1 files changed, 169 insertions, 27 deletions
diff --git a/library/RLCMAC_EncDec.cc b/library/RLCMAC_EncDec.cc index d25a7e07..dd32d8f8 100644 --- a/library/RLCMAC_EncDec.cc +++ b/library/RLCMAC_EncDec.cc @@ -207,17 +207,23 @@ static CodingScheme::enum_type payload_len_2_coding_scheme(size_t payload_len) { return CodingScheme::MCS__3; case 49: return CodingScheme::MCS__4; + case 60: /* fall through */ case 61: return CodingScheme::MCS__5; + case 78: /* fall through */ case 79: return CodingScheme::MCS__6; + case 118: /* fall through */ case 119: return CodingScheme::MCS__7; - case 142: + case 142: /* fall through */ + case 143: return CodingScheme::MCS__8; + case 154: /* fall through */ case 155: return CodingScheme::MCS__9; default: + fprintf(stderr, "ERROR: Unknown CodingSCheme for payload_len=%zu\n", payload_len); return CodingScheme::CS__1; } } @@ -438,6 +444,29 @@ static void put_egprs_data_block(const TTCN_Buffer& aligned_data_block_buffer, u dst_ttcn_buffer.increase_length(length_bytes); } +/* Append padding bytes and spare bits at the end of ttcn_buffer, based on requested CS */ +static void encode_trailing_padding_spb(TTCN_Buffer& ttcn_buffer, CodingScheme cs) +{ + uint8_t buf[256]; /* enough to fit any RLCMAC buffer*/ + uint32_t blk_len = RLCMAC__Templates::f__rlcmac__cs__mcs2block__len(cs); + uint32_t blk_len_no_spb = RLCMAC__Templates::f__rlcmac__cs__mcs2block__len__no__spare__bits(cs); + uint32_t data_len = ttcn_buffer.get_len(); + + if (data_len > blk_len_no_spb) { + fprintf(stderr, "Buffer too large for requested CS! %s (%s:%u)\n", __func__, __FILE__, __LINE__); + // TODO: throw exception? + return; + } + + for (int i = 0; i < blk_len_no_spb - data_len; i++) + buf[i] = 0x2b; /* Padding bits if needed */ + for (int i = blk_len_no_spb - data_len; i < blk_len - data_len; i++) + buf[i] = 0x00; /* Spare bits if needed */ + + const OCTETSTRING& pad_octstr = OCTETSTRING(blk_len - data_len, buf); + ttcn_buffer.put_string(pad_octstr); +} + ///////////////////// // DECODE ///////////////////// @@ -450,6 +479,8 @@ RlcmacDlDataBlock dec__RlcmacDlDataBlock(const OCTETSTRING& stream) TTCN_Buffer ttcn_buffer(stream); int num_llc_blocks = 0; + ret_val.cs() = payload_len_2_coding_scheme(stream.lengthof()); + /* use automatic/generated decoder for header */ ret_val.mac__hdr().decode(DlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW); @@ -475,6 +506,7 @@ RlcmacDlDataBlock dec__RlcmacDlDataBlock(const OCTETSTRING& stream) /* 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.hdr() = OMIT_VALUE; lb.payload() = OCTETSTRING(length, ttcn_buffer.get_read_data()); ttcn_buffer.increase_pos(length); ret_val.blocks()[0] = lb; @@ -482,8 +514,17 @@ RlcmacDlDataBlock dec__RlcmacDlDataBlock(const OCTETSTRING& stream) 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(); + + /* LI[0]=0 indicates: The current LLC PDU would fit within + current RLC data block but the addition of the length + indicator octet (to indicate the LLC PDU boundary) causes the + LLC PDU to extend into another RLC data block */ + if (i == 0 && length == 0) + length = ttcn_buffer.get_read_len(); + 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); } @@ -496,20 +537,54 @@ RlcmacDlDataBlock dec__RlcmacDlDataBlock(const OCTETSTRING& stream) static EgprsDlMacDataHeader dec__EgprsDlMacDataHeader_type1(const OCTETSTRING& stream) { + TTCN_Buffer ttcn_buffer(stream); EgprsDlMacDataHeader ret_val; + const struct gprs_rlc_dl_header_egprs_1 *egprs1; + uint8_t tmp; - fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__); + egprs1 = static_cast<const struct gprs_rlc_dl_header_egprs_1 *> + ((const void *)ttcn_buffer.get_data()); + ret_val.header__type() = EgprsHeaderType::RLCMAC__HDR__TYPE__1; + ret_val.tfi() = egprs1->tfi_lo << 1 | egprs1->tfi_hi << 0; + ret_val.rrbp() = egprs1->rrbp; + tmp = egprs1->es_p; + ret_val.esp() = BITSTRING(2, &tmp); + ret_val.usf() = egprs1->usf; + ret_val.bsn1() = egprs1->bsn1_lo << 10 | egprs1->bsn1_mid << 2 | egprs1->bsn1_hi; + ret_val.bsn2__offset() = egprs1->bsn2_lo << 7 | egprs1->bsn2_hi; + ret_val.pr() = egprs1->pr; + ret_val.cps() = egprs1->cps; + ret_val.spb() = OMIT_VALUE; + + ttcn_buffer.increase_pos(sizeof(*egprs1)); return ret_val; } static EgprsDlMacDataHeader dec__EgprsDlMacDataHeader_type2(const OCTETSTRING& stream) { + TTCN_Buffer ttcn_buffer(stream); EgprsDlMacDataHeader ret_val; + const struct gprs_rlc_dl_header_egprs_2 *egprs2; + uint8_t tmp; - fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__); + egprs2 = static_cast<const struct gprs_rlc_dl_header_egprs_2 *> + ((const void *)ttcn_buffer.get_data()); + ret_val.header__type() = EgprsHeaderType::RLCMAC__HDR__TYPE__2; + ret_val.tfi() = egprs2->tfi_lo << 1 | egprs2->tfi_hi << 0; + ret_val.rrbp() = egprs2->rrbp; + tmp = egprs2->es_p; + ret_val.esp() = BITSTRING(2, &tmp); + ret_val.usf() = egprs2->usf; + ret_val.bsn1() = egprs2->bsn1_lo << 10 | egprs2->bsn1_mid << 2 | egprs2->bsn1_hi; + ret_val.bsn2__offset() = 0; /*TODO: mark optional and not set ? */ + ret_val.pr() = egprs2->pr; + ret_val.cps() = egprs2->cps; + ret_val.spb() = OMIT_VALUE; + + ttcn_buffer.increase_pos(sizeof(*egprs2)); return ret_val; } @@ -541,7 +616,7 @@ EgprsDlMacDataHeader dec__EgprsDlMacDataHeader_type3(const OCTETSTRING& stream) } static -RlcmacDlEgprsDataBlock dec__RlcmacDlEgprsDataBlock(const OCTETSTRING& stream, CodingScheme::enum_type mcs) +RlcmacDlEgprsDataBlock dec__RlcmacDlEgprsDataBlock(const OCTETSTRING& stream) { RlcmacDlEgprsDataBlock ret_val; TTCN_Buffer ttcn_buffer(stream); @@ -551,7 +626,8 @@ RlcmacDlEgprsDataBlock dec__RlcmacDlEgprsDataBlock(const OCTETSTRING& stream, Co unsigned int num_calls; const uint8_t *ti_e; - switch (mcs) { + ret_val.mcs() = payload_len_2_coding_scheme(stream.lengthof()); + switch (ret_val.mcs()) { case CodingScheme::MCS__0: case CodingScheme::MCS__1: case CodingScheme::MCS__2: @@ -569,7 +645,7 @@ RlcmacDlEgprsDataBlock dec__RlcmacDlEgprsDataBlock(const OCTETSTRING& stream, Co ret_val.mac__hdr() = dec__EgprsDlMacDataHeader_type1(stream); break; } - setup_rlc_mac_priv(mcs, ret_val.mac__hdr().header__type(), false, + setup_rlc_mac_priv(ret_val.mcs(), ret_val.mac__hdr().header__type(), false, &num_calls, &data_block_bits, data_block_offsets); get_egprs_data_block(ttcn_buffer, data_block_offsets[0], data_block_bits, aligned_buffer); @@ -594,13 +670,26 @@ RlcmacDlEgprsDataBlock dec__RlcmacDlEgprsDataBlock(const OCTETSTRING& stream, Co } /* RLC blocks at end */ - 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 > aligned_buffer.get_read_len()) - length = aligned_buffer.get_read_len(); - ret_val.blocks()[i].payload() = OCTETSTRING(length, aligned_buffer.get_read_data()); - aligned_buffer.increase_pos(length); + if (ret_val.e() == true) { + EgprsLlcBlock lb; + unsigned int length = aligned_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.hdr() = OMIT_VALUE; + lb.payload() = OCTETSTRING(length, ttcn_buffer.get_read_data()); + aligned_buffer.increase_pos(length); + ret_val.blocks()[0] = lb; + } else { + /* RLC blocks at end */ + 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 > aligned_buffer.get_read_len()) + length = aligned_buffer.get_read_len(); + ret_val.blocks()[i].payload() = OCTETSTRING(length, aligned_buffer.get_read_data()); + aligned_buffer.increase_pos(length); + } } } @@ -611,10 +700,10 @@ RlcmacDlBlock dec__RlcmacDlBlock(const OCTETSTRING& stream) { RlcmacDlBlock ret_val; size_t stream_len = stream.lengthof(); - CodingScheme::enum_type mcs = payload_len_2_coding_scheme(stream_len); + CodingScheme::enum_type cs_mcs = payload_len_2_coding_scheme(stream_len); unsigned char pt; - switch (mcs) { + switch (cs_mcs) { case CodingScheme::CS__1: case CodingScheme::CS__2: case CodingScheme::CS__3: @@ -635,7 +724,7 @@ RlcmacDlBlock dec__RlcmacDlBlock(const OCTETSTRING& stream) case CodingScheme::MCS__7: case CodingScheme::MCS__8: case CodingScheme::MCS__9: - ret_val.data__egprs() = dec__RlcmacDlEgprsDataBlock(stream, mcs); + ret_val.data__egprs() = dec__RlcmacDlEgprsDataBlock(stream); break; } return ret_val; @@ -655,6 +744,8 @@ RlcmacUlDataBlock dec__RlcmacUlDataBlock(const OCTETSTRING& stream) stream.log(); TTCN_Logger::end_event(); + ret_val.cs() = payload_len_2_coding_scheme(stream.lengthof()); + /* use automatic/generated decoder for header */ ret_val.mac__hdr().decode(UlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW); @@ -715,6 +806,7 @@ RlcmacUlDataBlock dec__RlcmacUlDataBlock(const OCTETSTRING& stream) /* 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.hdr() = OMIT_VALUE; lb.payload() = OCTETSTRING(length, ttcn_buffer.get_read_data()); ttcn_buffer.increase_pos(length); ret_val.blocks()[0] = lb; @@ -792,7 +884,7 @@ EgprsUlMacDataHeader dec__EgprsUlMacDataHeader_type3(const OCTETSTRING& stream) return ret_val; } -RlcmacUlEgprsDataBlock dec__RlcmacUlEgprsDataBlock(const OCTETSTRING& stream, CodingScheme::enum_type mcs) +RlcmacUlEgprsDataBlock dec__RlcmacUlEgprsDataBlock(const OCTETSTRING& stream) { RlcmacUlEgprsDataBlock ret_val; TTCN_Buffer ttcn_buffer(stream); @@ -802,7 +894,8 @@ RlcmacUlEgprsDataBlock dec__RlcmacUlEgprsDataBlock(const OCTETSTRING& stream, Co unsigned int num_calls; const uint8_t *ti_e; - switch (mcs) { + ret_val.mcs() = payload_len_2_coding_scheme(stream.lengthof()); + switch (ret_val.mcs()) { case CodingScheme::MCS__1: case CodingScheme::MCS__2: case CodingScheme::MCS__3: @@ -819,7 +912,7 @@ RlcmacUlEgprsDataBlock dec__RlcmacUlEgprsDataBlock(const OCTETSTRING& stream, Co ret_val.mac__hdr() = dec__EgprsUlMacDataHeader_type1(stream); break; } - setup_rlc_mac_priv(mcs, ret_val.mac__hdr().header__type(), true, + setup_rlc_mac_priv(ret_val.mcs(), ret_val.mac__hdr().header__type(), true, &num_calls, &data_block_bits, data_block_offsets); get_egprs_data_block(ttcn_buffer, data_block_offsets[0], data_block_bits, aligned_buffer); @@ -867,6 +960,7 @@ RlcmacUlEgprsDataBlock dec__RlcmacUlEgprsDataBlock(const OCTETSTRING& stream, Co /* 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.hdr() = OMIT_VALUE; lb.payload() = OCTETSTRING(length, aligned_buffer.get_read_data()); aligned_buffer.increase_pos(length); ret_val.blocks()[0] = lb; @@ -889,10 +983,10 @@ RlcmacUlBlock dec__RlcmacUlBlock(const OCTETSTRING& stream) { RlcmacUlBlock ret_val; size_t stream_len = stream.lengthof(); - CodingScheme::enum_type mcs = payload_len_2_coding_scheme(stream_len); + CodingScheme::enum_type cs_mcs = payload_len_2_coding_scheme(stream_len); unsigned char pt; - switch (mcs) { + switch (cs_mcs) { case CodingScheme::CS__1: case CodingScheme::CS__2: case CodingScheme::CS__3: @@ -912,7 +1006,7 @@ RlcmacUlBlock dec__RlcmacUlBlock(const OCTETSTRING& stream) case CodingScheme::MCS__7: case CodingScheme::MCS__8: case CodingScheme::MCS__9: - ret_val.data__egprs() = dec__RlcmacUlEgprsDataBlock(stream, mcs); + ret_val.data__egprs() = dec__RlcmacUlEgprsDataBlock(stream); break; } @@ -964,6 +1058,8 @@ OCTETSTRING enc__RlcmacDlDataBlock(const RlcmacDlDataBlock& si) } } + encode_trailing_padding_spb(ttcn_buffer, in.cs()); + ttcn_buffer.get_string(ret_val); return ret_val; } @@ -1034,6 +1130,8 @@ OCTETSTRING enc__RlcmacDlEgprsDataBlock(const RlcmacDlEgprsDataBlock& si) } } + encode_trailing_padding_spb(ttcn_buffer, in.mcs()); + ttcn_buffer.get_string(ret_val); return ret_val; } @@ -1127,6 +1225,8 @@ OCTETSTRING enc__RlcmacUlDataBlock(const RlcmacUlDataBlock& si) } } + encode_trailing_padding_spb(ttcn_buffer, in.cs()); + ttcn_buffer.get_string(ret_val); return ret_val; } @@ -1134,13 +1234,48 @@ OCTETSTRING enc__RlcmacUlDataBlock(const RlcmacUlDataBlock& si) static void enc__RlcmacUlEgprsDataHeader_type1(const EgprsUlMacDataHeader& si, TTCN_Buffer& ttcn_buffer) { - fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__); + struct gprs_rlc_ul_header_egprs_1 egprs1; + + egprs1.r = bs2uint8(si.r__ri()); + egprs1.si = bs2uint8(si.foi__si()); + egprs1.cv = si.countdown(); + egprs1.tfi_hi = si.tfi() >> 0; + egprs1.tfi_lo = si.tfi() >> 2; + egprs1.bsn1_hi = si.bsn1() >> 0; + egprs1.bsn1_lo = si.bsn1() >> 5; + egprs1.bsn2_hi = si.bsn2__offset() >> 0; + egprs1.bsn2_lo = si.bsn2__offset() >> 2; + egprs1.cps = si.cps(); + egprs1.rsb = bs2uint8(si.rsb()); + egprs1.pi = si.pfi__ind(); + egprs1.spare_hi = 0; + egprs1.spare_lo = 0; + egprs1.dummy = 0; + + ttcn_buffer.put_s(sizeof(egprs1), (const unsigned char *)&egprs1); } static void enc__RlcmacUlEgprsDataHeader_type2(const EgprsUlMacDataHeader& si, TTCN_Buffer& ttcn_buffer) { - fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__); + struct gprs_rlc_ul_header_egprs_2 egprs2; + + egprs2.r = bs2uint8(si.r__ri()); + egprs2.si = bs2uint8(si.foi__si()); + egprs2.cv = si.countdown(); + egprs2.tfi_hi = si.tfi() >> 0; + egprs2.tfi_lo = si.tfi() >> 2; + egprs2.bsn1_hi = si.bsn1() >> 0; + egprs2.bsn1_lo = si.bsn1() >> 5; + egprs2.cps_hi = si.cps() >> 0; + egprs2.cps_lo = si.cps() >> 2; + egprs2.rsb = bs2uint8(si.rsb()); + egprs2.pi = si.pfi__ind(); + egprs2.spare_hi = 0; + egprs2.spare_lo = 0; + egprs2.dummy = 0; + + ttcn_buffer.put_s(sizeof(egprs2), (const unsigned char *)&egprs2); } static @@ -1175,7 +1310,6 @@ OCTETSTRING enc__RlcmacUlEgprsDataBlock(const RlcmacUlEgprsDataBlock& si) unsigned int data_block_bits, data_block_offsets[2]; unsigned int num_calls; CodingScheme mcs; - boolean tlli_ind, e; mcs = RLCMAC__Templates::f__rlcmac__cps__htype__to__mcs(in.mac__hdr().cps(), in.mac__hdr().header__type()); //fprintf(stderr, "RLCMAC: infered MCS %s (%d)\n", mcs.enum_to_str(static_cast<CodingScheme::enum_type>(mcs.as_int())), mcs.as_int()); @@ -1209,7 +1343,7 @@ OCTETSTRING enc__RlcmacUlEgprsDataBlock(const RlcmacUlEgprsDataBlock& si) } /* Put first TI + E byte */ - aligned_buffer.put_c(tlli_ind << 1 | e << 0); /* M=0, E=1 LEN=0 */ + aligned_buffer.put_c((in.tlli__ind() & 0x01) << 1 | (in.e() & 0x01) << 0); //printbuffer("After encoding first byte", aligned_buffer); if (in.e() == false) { @@ -1251,7 +1385,13 @@ OCTETSTRING enc__RlcmacUlEgprsDataBlock(const RlcmacUlEgprsDataBlock& si) if (in.tlli__ind()) { - aligned_buffer.put_string(in.tlli()); + /* The TLLI is encoded in little endian for EGPRS (see + * TS 44.060, figure 10.3a.2.1, note 2) */ + OCTETSTRING tlli = in.tlli(); + aligned_buffer.put_c(tlli[3].get_octet()); + aligned_buffer.put_c(tlli[2].get_octet()); + aligned_buffer.put_c(tlli[1].get_octet()); + aligned_buffer.put_c(tlli[0].get_octet()); } if (in.mac__hdr().pfi__ind()) { @@ -1274,6 +1414,8 @@ OCTETSTRING enc__RlcmacUlEgprsDataBlock(const RlcmacUlEgprsDataBlock& si) put_egprs_data_block(aligned_buffer, data_block_offsets[0], data_block_bits, ttcn_buffer); //printbuffer("after merging data block", ttcn_buffer); + encode_trailing_padding_spb(ttcn_buffer, in.mcs()); + ttcn_buffer.get_string(ret_val); return ret_val; } |