blob: 4ae65b1f62788a40a072cb345c2b0cd5c1f87bb6 [file] [log] [blame]
Harald Welte43e060a2017-07-30 22:38:03 +02001#include "RLCMAC_Types.hh"
2#include "GSM_Types.hh"
3/* Decoding of TS 44.060 GPRS RLC/MAC blocks, portions requiring manual functions
4 * beyond what TITAN RAW coder can handle internally.
5 *
6 * (C) 2017 by Harald Welte <laforge@gnumonks.org>
Harald Welte34b5a952019-05-27 11:54:11 +02007 * All rights reserved.
8 *
9 * Released under the terms of GNU General Public License, Version 2 or
10 * (at your option) any later version.
11 *
12 * SPDX-License-Identifier: GPL-2.0-or-later
Harald Welte43e060a2017-07-30 22:38:03 +020013 */
14
15namespace RLCMAC__Types {
16
17OCTETSTRING enc__RlcmacDlDataBlock(const RlcmacDlDataBlock& si)
18{
19 RlcmacDlDataBlock in = si;
20 OCTETSTRING ret_val;
21 TTCN_Buffer ttcn_buffer;
22 int i;
23
24 /* Fix 'e' bit of initial header based on following blocks */
Harald Welte244cd8a2017-08-26 09:25:20 +020025 if (!in.blocks().is_bound() ||
26 (in.blocks().size_of() == 1 && !in.blocks()[0].hdr().is_bound()))
Harald Welte43e060a2017-07-30 22:38:03 +020027 in.mac__hdr().hdr__ext().e() = true;
28 else
29 in.mac__hdr().hdr__ext().e() = false;
30
31 /* use automatic/generated decoder for header */
32 in.mac__hdr().encode(DlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
33
34 /* Add LI octets, if any */
35 if (in.blocks().is_bound() &&
36 (in.blocks().size_of() != 1 || in.blocks()[0].hdr().is_bound())) {
37 /* first write LI octets */
38 for (i = 0; i < in.blocks().size_of(); i++) {
39 /* fix the 'E' bit in case it is not clear */
40 if (i < in.blocks().size_of()-1)
Harald Welte060e27a2018-03-03 20:38:19 +010041 in.blocks()[i].hdr()().e() = false;
Harald Welte43e060a2017-07-30 22:38:03 +020042 else
Harald Welte060e27a2018-03-03 20:38:19 +010043 in.blocks()[i].hdr()().e() = true;
Harald Welte439e5462018-03-08 23:21:17 +010044 in.blocks()[i].hdr()().encode(LlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
Harald Welte43e060a2017-07-30 22:38:03 +020045 }
46 }
47 if (in.blocks().is_bound()) {
48 for (i = 0; i < in.blocks().size_of(); i++) {
49 if (!in.blocks()[i].is_bound())
50 continue;
51 ttcn_buffer.put_string(in.blocks()[i].payload());
52 }
53 }
54
55 ttcn_buffer.get_string(ret_val);
56 return ret_val;
57}
58
59RlcmacDlDataBlock dec__RlcmacDlDataBlock(const OCTETSTRING& stream)
60{
61 RlcmacDlDataBlock ret_val;
62 TTCN_Buffer ttcn_buffer(stream);
63 int num_llc_blocks = 0;
64
65 /* use automatic/generated decoder for header */
66 ret_val.mac__hdr().decode(DlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
67
68 /* optional extension octets, containing LI+M+E of Llc blocks */
69 if (ret_val.mac__hdr().hdr__ext().e() == false) {
70 /* extension octet follows, i.e. optional Llc length octets */
71 while (1) {
72 /* decode one more extension octet with LlcBlocHdr inside */
73 LlcBlock lb;
Harald Welte439e5462018-03-08 23:21:17 +010074 lb.hdr()().decode(LlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
Harald Welte43e060a2017-07-30 22:38:03 +020075 ret_val.blocks()[num_llc_blocks++] = lb;
76
77 /* if E == '1'B, we can proceed further */
Harald Welte060e27a2018-03-03 20:38:19 +010078 if (lb.hdr()().e() == true)
Harald Welte43e060a2017-07-30 22:38:03 +020079 break;
80 }
81 }
82
83 /* RLC blocks at end */
84 if (ret_val.mac__hdr().hdr__ext().e() == true) {
85 LlcBlock lb;
86 unsigned int length = ttcn_buffer.get_read_len();
87 /* LI not present: The Upper Layer PDU that starts with the current RLC data block either
88 * fills the current RLC data block precisely or continues in the following in-sequence RLC
89 * data block */
90 lb.payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
91 ttcn_buffer.increase_pos(length);
92 ret_val.blocks()[0] = lb;
93 } else {
94 if (ret_val.blocks().is_bound()) {
95 for (int i = 0; i < ret_val.blocks().size_of(); i++) {
Harald Welte060e27a2018-03-03 20:38:19 +010096 unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
Harald Welte43e060a2017-07-30 22:38:03 +020097 if (length > ttcn_buffer.get_read_len())
98 length = ttcn_buffer.get_read_len();
99 ret_val.blocks()[i].payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
100 ttcn_buffer.increase_pos(length);
101 }
102 }
103 }
104
105 return ret_val;
106}
107
108
109OCTETSTRING enc__RlcmacUlDataBlock(const RlcmacUlDataBlock& si)
110{
111 RlcmacUlDataBlock in = si;
112 OCTETSTRING ret_val;
113 TTCN_Buffer ttcn_buffer;
114 int i;
115
Harald Welte060e27a2018-03-03 20:38:19 +0100116 if (!in.blocks().is_bound()) {
117 /* we don't have nay blocks: Add length value (zero) */
118 in.mac__hdr().e() = false; /* E=0: extension octet follows */
119 } else if (in.blocks().size_of() == 1 && in.blocks()[0].hdr() == OMIT_VALUE) {
120 /* If there's only a single block, and that block has no HDR value defined, */
121 in.mac__hdr().e() = true; /* E=0: extension octet follows */
122 } else {
123 /* Length value */
Harald Welte43e060a2017-07-30 22:38:03 +0200124 in.mac__hdr().e() = false;
Harald Welte060e27a2018-03-03 20:38:19 +0100125 }
Harald Welte43e060a2017-07-30 22:38:03 +0200126
127 /* Fix other presence indications */
Harald Welte2072ab62017-07-31 18:33:35 +0200128 in.mac__hdr().tlli__ind() = in.tlli().is_bound() && in.tlli() != OMIT_VALUE;
129 in.mac__hdr().pfi__ind() = in.pfi().is_bound() && in.pfi() != OMIT_VALUE;
Harald Welte43e060a2017-07-30 22:38:03 +0200130
Harald Welte060e27a2018-03-03 20:38:19 +0100131 /* use automatic/generated encoder for header */
Harald Welte43e060a2017-07-30 22:38:03 +0200132 in.mac__hdr().encode(UlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
133
Harald Welte060e27a2018-03-03 20:38:19 +0100134 if (in.mac__hdr().e() == false) {
135 /* Add LI octets, if any */
136 if (!in.blocks().is_bound()) {
137 ttcn_buffer.put_c(0x01); /* M=0, E=1 LEN=0 */
138 } else {
139 for (i = 0; i < in.blocks().size_of(); i++) {
140#if 0
141 /* check for penultimate block */
142 if (i == in.blocks().size_of()-2) {
143 /* if last block has no header, no more LI */
144 if (in.blocks()[i+1].hdr() == OMIT_VALUE) {
145 in.blocks()[i].hdr()().more() = true;
146 } else {
147 /* header present, we have to encode LI */
148 in.blocks()[i].hdr()().more() = false;
149 in.blocks()[i].hdr()().length__ind() =
150 in.blocks()[i+1].payload().lengthof();
151 }
152 } else if (i < in.blocks().size_of()-2) {
153 /* one of the first blocks, before the penultimate or last */
154 in.blocks()[i].hdr()().e() = false; /* LI present */
155 /* re-compute length */
156 in.blocks()[i].hdr()().length__ind() =
157 in.blocks()[i+1].payload().lengthof();
158 }
159 /* Encode LI octet if E=0 */
160 }
161#endif
162 if (in.blocks()[i].hdr() != OMIT_VALUE) {
163 in.blocks()[i].hdr()().encode(LlcBlockHdr_descr_, ttcn_buffer,
164 TTCN_EncDec::CT_RAW);
165 }
166 }
Harald Welte43e060a2017-07-30 22:38:03 +0200167 }
168 }
169
170 if (in.mac__hdr().tlli__ind()) {
Harald Welteacc93ab2018-03-02 21:39:09 +0100171 ttcn_buffer.put_string(in.tlli());
Harald Welte43e060a2017-07-30 22:38:03 +0200172 }
173
174 if (in.mac__hdr().pfi__ind()) {
175 in.pfi().encode(RlcmacUlDataBlock_pfi_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
176 }
177
178 if (in.blocks().is_bound()) {
179 for (i = 0; i < in.blocks().size_of(); i++) {
180 if (!in.blocks()[i].is_bound())
181 continue;
182 ttcn_buffer.put_string(in.blocks()[i].payload());
183 }
184 }
185
186 ttcn_buffer.get_string(ret_val);
187 return ret_val;
188}
189
190RlcmacUlDataBlock dec__RlcmacUlDataBlock(const OCTETSTRING& stream)
191{
192 RlcmacUlDataBlock ret_val;
193 TTCN_Buffer ttcn_buffer(stream);
194 int num_llc_blocks = 0;
195
196 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
197 TTCN_Logger::log_event_str("==================================\n"
198 "dec_RlcmacUlDataBlock(): Stream before decoding: ");
199 stream.log();
200 TTCN_Logger::end_event();
201
202 /* use automatic/generated decoder for header */
203 ret_val.mac__hdr().decode(UlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
204
205 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
206 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): Stream after decoding hdr: ");
207 ttcn_buffer.log();
208 TTCN_Logger::end_event();
209 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
210 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): ret_val after decoding hdr: ");
211 ret_val.log();
212 TTCN_Logger::end_event();
213
214 /* Manually decoder remainder of ttcn_buffer, containing optional header octets,
215 * optional tlli, optional pfi and LLC Blocks */
216
217 /* optional extension octets, containing LI+M+E of Llc blocks */
218 if (ret_val.mac__hdr().e() == false) {
219 /* extension octet follows, i.e. optional Llc length octets */
220 while (1) {
221 /* decode one more extension octet with LlcBlocHdr inside */
222 LlcBlock lb;
Harald Welte439e5462018-03-08 23:21:17 +0100223 lb.hdr()().decode(LlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
Harald Welte43e060a2017-07-30 22:38:03 +0200224 ret_val.blocks()[num_llc_blocks++] = lb;
225
226 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
227 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): Stream after decoding ExtOct: ");
228 ttcn_buffer.log();
229 TTCN_Logger::end_event();
230 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
231 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): ret_val after decoding ExtOct: ");
232 ret_val.log();
233 TTCN_Logger::end_event();
234
235 /* if E == '1'B, we can proceed further */
Harald Welte060e27a2018-03-03 20:38:19 +0100236 if (lb.hdr()().e() == true)
Harald Welte43e060a2017-07-30 22:38:03 +0200237 break;
238 }
239 }
240
241 /* parse optional TLLI */
242 if (ret_val.mac__hdr().tlli__ind()) {
Harald Welteacc93ab2018-03-02 21:39:09 +0100243 ret_val.tlli() = OCTETSTRING(4, ttcn_buffer.get_read_data());
Harald Welte43e060a2017-07-30 22:38:03 +0200244 ttcn_buffer.increase_pos(4);
245 }
246 /* parse optional PFI */
247 if (ret_val.mac__hdr().pfi__ind()) {
248 ret_val.pfi().decode(RlcmacUlDataBlock_pfi_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
249 }
250
251 /* RLC blocks at end */
252 if (ret_val.mac__hdr().e() == true) {
253 LlcBlock lb;
254 unsigned int length = ttcn_buffer.get_read_len();
255 /* LI not present: The Upper Layer PDU that starts with the current RLC data block either
256 * fills the current RLC data block precisely or continues in the following in-sequence RLC
257 * data block */
258 lb.payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
259 ttcn_buffer.increase_pos(length);
260 ret_val.blocks()[0] = lb;
261 } else {
262 if (ret_val.blocks().is_bound()) {
263 for (int i = 0; i < ret_val.blocks().size_of(); i++) {
Harald Welte060e27a2018-03-03 20:38:19 +0100264 unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
Harald Welte43e060a2017-07-30 22:38:03 +0200265 if (length > ttcn_buffer.get_read_len())
266 length = ttcn_buffer.get_read_len();
267 ret_val.blocks()[i].payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
268 ttcn_buffer.increase_pos(length);
269 }
270 }
271 }
272
273 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
274 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): Stream before return: ");
275 ttcn_buffer.log();
276 TTCN_Logger::end_event();
277 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
278 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): ret_val before return: ");
279 ret_val.log();
280 TTCN_Logger::end_event();
281
282 return ret_val;
283}
284
Harald Welte78a1af62017-07-31 17:33:56 +0200285OCTETSTRING enc__RlcmacUlBlock(const RlcmacUlBlock& si)
286{
287 if (si.ischosen(RlcmacUlBlock::ALT_data))
288 return enc__RlcmacUlDataBlock(si.data());
289 else
290 return enc__RlcmacUlCtrlBlock(si.ctrl());
291}
292
293OCTETSTRING enc__RlcmacDlBlock(const RlcmacDlBlock& si)
294{
295 if (si.ischosen(RlcmacDlBlock::ALT_data))
296 return enc__RlcmacDlDataBlock(si.data());
297 else
298 return enc__RlcmacDlCtrlBlock(si.ctrl());
299}
300
301
302RlcmacUlBlock dec__RlcmacUlBlock(const OCTETSTRING& stream)
303{
304 RlcmacUlBlock ret_val;
305 unsigned char pt = stream[0].get_octet() >> 6;
306
307 if (pt == MacPayloadType::MAC__PT__RLC__DATA)
308 ret_val.data() = dec__RlcmacUlDataBlock(stream);
309 else
310 ret_val.ctrl() = dec__RlcmacUlCtrlBlock(stream);
311
312 return ret_val;
313}
314
315RlcmacDlBlock dec__RlcmacDlBlock(const OCTETSTRING& stream)
316{
317 RlcmacDlBlock ret_val;
318 unsigned char pt = stream[0].get_octet() >> 6;
319
320 if (pt == MacPayloadType::MAC__PT__RLC__DATA)
321 ret_val.data() = dec__RlcmacDlDataBlock(stream);
322 else
323 ret_val.ctrl() = dec__RlcmacDlCtrlBlock(stream);
324
325 return ret_val;
326}
327
Harald Welte43e060a2017-07-30 22:38:03 +0200328
329} // namespace