Home » Eclipse Projects » Eclipse Titan » Incorrect decoding of an unaligned bit-field (BIT5)
Incorrect decoding of an unaligned bit-field (BIT5) [message #1826490] |
Sat, 25 April 2020 18:50 |
Vadim Yanitskiy Messages: 5 Registered: May 2018 |
Junior Member |
|
|
I am currently working on TTCN-3 test cases for the OsmoPCU (Osmocom Packet Control Unit) project:
https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/17706
where I need to decode and verify the contents of RR Immediate Assignment message, in particular its CSN.1 encoded part called "Rect Octets" (see 3GPP TS 44.018, section 10.5.2.16). Unfortunately, TITAN's RAW codec fails to decode one of the message fields correctly (compared to Wireshark). According to the law of Sod, this is exactly the field I need to verify in my unit tests (Extended RA). All other fields seem to be decoded correctly.
Here is how the packet looks like in Wireshark (most important part of it):
IA Rest Octets
L... .... = First Discriminator Bit: Low
.H.. .... = Second Discriminator Bit: High
..0. .... = Discriminator bit: EGPRS Packet Uplink Assignment or Multiple blocks Packet Downlink Assignment
...0 .... = Downlink/Uplink: EGPRS Packet Uplink Assignment
EGPRS Packet Uplink Assignment
.... 0001 1... .... = Extended_RA: 3 // <------------ (!)
.0.. .... = Access Technologies Request: Not Present
..1. .... = TFI/Multiblock: TFI Assignment Present
...0 0000 = TFI_Assignment: 0
0... .... = Polling: no action is required from MS
.0.. .... = Allocation Type: Dynamic Allocation (mandatory after Rel-4)
..00 0... = USF: 0
.... .0.. = USF_granularity: the mobile station shall transmit one RLC/MAC block
.... ..0. = P0: Not Present
.... ...0 001. .... = Egprs_Modulation_and_Coding_Scheme: MCS-2 (1)
...0 .... = TLLI_Block_Channel_Coding: mobile station shall use CS-1 in GPRS TBF mode or MCS-1 in EGPRS TBF mode
.... 0... = BEP_PERIOD2: Not Present
.... .0.. = Resegment: Retransmitted RLC data blocks shall not be re-segmented
.... ..00 000. .... = Egprs_Windows_Size: 64 (0)
...0 .... = Alpha: Not Present
.... 0000 0... .... = Gamma: 0 dB (0)
.0.. .... = Timing Advance Index: Not Present
..0. .... = TBF Starting Time: Not Present
...L .... = Additions in Rel-7: Not Present
and here is what TITAN's logs:
rest_octets := {
presence := '01'B,
ll := omit,
lh := {
presence := '00'B,
egprs_ul := {
ext_ra := '10001'B, // <------ (!)
ats_present := '0'B,
ats := omit,
presence := '1'B,
dynamic := {
tfi_assignment := 0,
polling := '0'B,
spare := '0'B,
usf := 0,
usf_granularity := '0'B,
p0_present := '0'B,
p0 := omit,
pr_mode := omit,
egprs_ch_coding_cmd := CH_CODING_MCS2 (1),
tlli_block_chan_coding := '0'B,
bep_period2_present := '0'B,
bep_period2 := omit,
resegment := '0'B,
egprs_window_size := EGPRS_WS_64 (0),
alpha_present := '0'B,
alpha := omit,
gamma := 0,
ta_index_present := '0'B,
ta_index := omit,
tbf_starting_time_present := '0'B,
tbf_starting_time := omit
},
multiblock := omit
},
multiblock_dl_ass := omit
},
hl := omit,
hh := omit
}
As can be seen, Extended_RA does not match ('00011'B vs '10001'B). I did a little investigation, and managed to reproduce the problem with a simple record containing several bit-fields:
private type record TestRecord {
BIT2 msg_disc, // xx.. .... .... ....
BIT1 field1, // ..x. .... .... ....
BIT1 field2, // ...x .... .... ....
BIT5 field3, // .... xxxx x... .... (!)
BIT3 field4, // .... .... .xxx ....
BIT4 field5 // .... .... .... xxxx
} with {
encode "RAW";
variant "FIELDORDER(msb)"
variant "BYTEORDER(last)"
variant "BITORDER(msb)"
};
private external function enc_TestRecord(in TestRecord rec) return bitstring
with { extension "prototype(convert) encode(RAW)" };
private external function dec_TestRecord(in bitstring rec) return TestRecord
with { extension "prototype(convert) decode(RAW)" };
/* Some test sequences (recognisable pattern) */
private const bitstring test_seq00 := '0000000000000000'B;
private const bitstring test_seq01 := '0101010101010101'B; // (!)
private const bitstring test_seq11 := '1111111111111111'B;
private template TestRecord tr_TestSeq00 := {
msg_disc := '00'B,
field1 := '0'B,
field2 := '0'B,
field3 := '00000'B,
field4 := '000'B,
field5 := '0000'B
};
private template TestRecord tr_TestSeq01 := {
msg_disc := '01'B,
field1 := '0'B,
field2 := '1'B,
field3 := '01010'B,
field4 := '101'B,
field5 := '0101'B
};
private template TestRecord tr_TestSeq11 := {
msg_disc := '11'B,
field1 := '1'B,
field2 := '1'B,
field3 := '11111'B,
field4 := '111'B,
field5 := '1111'B
};
private function f_TC_bitstring_selftest(in bitstring seq, template TestRecord tr_rec)
{
var TestRecord rec_dec;
var bitstring seq_enc;
log("Testing sequence: ", seq);
/* decode -> encode a given test sequence */
rec_dec := dec_TestRecord(seq);
seq_enc := enc_TestRecord(rec_dec);
if (seq_enc != seq) {
setverdict(fail, "Encoded sequence does not match: ", seq_enc, " vs ", seq);
}
if (not match(rec_dec, tr_rec)) {
setverdict(fail, "Decoded record does not match: ", rec_dec);
}
setverdict(pass);
}
testcase TC_bitstring_selftest() runs on RAW_PCU_Test_CT
{
f_TC_bitstring_selftest(test_seq00, tr_TestSeq00); // pass
f_TC_bitstring_selftest(test_seq01, tr_TestSeq01); // fail
f_TC_bitstring_selftest(test_seq11, tr_TestSeq11); // pass
}
and here is the result:
MTC@DELL: Testing sequence: '0000000000000000'B
MTC@DELL: dec_TestRecord(): Stream before decoding: '0000000000000000'B
MTC@DELL: dec_TestRecord(): Decoded @PCU_Tests_RAW.TestRecord: { msg_disc := '00'B, field1 := '0'B, field2 := '0'B, field3 := '00000'B, field4 := '000'B, field5 := '0000'B }
MTC@DELL: enc_TestRecord(): Encoding @PCU_Tests_RAW.TestRecord: { msg_disc := '00'B, field1 := '0'B, field2 := '0'B, field3 := '00000'B, field4 := '000'B, field5 := '0000'B }
MTC@DELL: enc_TestRecord(): Stream after encoding: '0000000000000000'B
MTC@DELL: Testing sequence: '0101010101010101'B
MTC@DELL: dec_TestRecord(): Stream before decoding: '0101010101010101'B
MTC@DELL: dec_TestRecord(): Decoded @PCU_Tests_RAW.TestRecord: { msg_disc := '01'B, field1 := '0'B, field2 := '1'B, field3 := '00101'B, field4 := '101'B, field5 := '0101'B }
MTC@DELL: enc_TestRecord(): Encoding @PCU_Tests_RAW.TestRecord: { msg_disc := '01'B, field1 := '0'B, field2 := '1'B, field3 := '00101'B, field4 := '101'B, field5 := '0101'B }
MTC@DELL: enc_TestRecord(): Stream after encoding: '0101010101010101'B
MTC@DELL: Testing sequence: '1111111111111111'B
MTC@DELL: dec_TestRecord(): Stream before decoding: '1111111111111111'B
MTC@DELL: dec_TestRecord(): Decoded @PCU_Tests_RAW.TestRecord: { msg_disc := '11'B, field1 := '1'B, field2 := '1'B, field3 := '11111'B, field4 := '111'B, field5 := '1111'B }
MTC@DELL: enc_TestRecord(): Encoding @PCU_Tests_RAW.TestRecord: { msg_disc := '11'B, field1 := '1'B, field2 := '1'B, field3 := '11111'B, field4 := '111'B, field5 := '1111'B }
MTC@DELL: enc_TestRecord(): Stream after encoding: '1111111111111111'B
MTC@DELL: Test case TC_bitstring_selftest finished. Verdict: fail reason: Decoded record does not match: { msg_disc := '01'B, field1 := '0'B, field2 := '1'B, field3 := '
00101'B, field4 := '101'B, field5 := '0101'B }
Am I missing something? I have managed to work this around by using an integer type with fixed length instead of a bitstring, and also by splitting BIT5 into { BIT4, BIT1 }. But it still feels like a hack, and now I want to know why BIT5 does not work as expected.
Thanks in advance!
With best regards,
Vadim Yanitskiy.
|
|
| | | | |
Goto Forum:
Current Time: Wed Nov 13 15:26:36 GMT 2024
Powered by FUDForum. Page generated in 0.04293 seconds
|