blob: 4cdeae7e6dd9e3c796e9278433d0e32e070548b6 [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>
7 */
8
9namespace RLCMAC__Types {
10
11OCTETSTRING enc__RlcmacDlDataBlock(const RlcmacDlDataBlock& si)
12{
13 RlcmacDlDataBlock in = si;
14 OCTETSTRING ret_val;
15 TTCN_Buffer ttcn_buffer;
16 int i;
17
18 /* Fix 'e' bit of initial header based on following blocks */
Harald Welte244cd8a2017-08-26 09:25:20 +020019 if (!in.blocks().is_bound() ||
20 (in.blocks().size_of() == 1 && !in.blocks()[0].hdr().is_bound()))
Harald Welte43e060a2017-07-30 22:38:03 +020021 in.mac__hdr().hdr__ext().e() = true;
22 else
23 in.mac__hdr().hdr__ext().e() = false;
24
25 /* use automatic/generated decoder for header */
26 in.mac__hdr().encode(DlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
27
28 /* Add LI octets, if any */
29 if (in.blocks().is_bound() &&
30 (in.blocks().size_of() != 1 || in.blocks()[0].hdr().is_bound())) {
31 /* first write LI octets */
32 for (i = 0; i < in.blocks().size_of(); i++) {
33 /* fix the 'E' bit in case it is not clear */
34 if (i < in.blocks().size_of()-1)
35 in.blocks()[i].hdr().e() = false;
36 else
37 in.blocks()[i].hdr().e() = true;
38 in.blocks()[i].hdr().encode(LlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
39 }
40 }
41 if (in.blocks().is_bound()) {
42 for (i = 0; i < in.blocks().size_of(); i++) {
43 if (!in.blocks()[i].is_bound())
44 continue;
45 ttcn_buffer.put_string(in.blocks()[i].payload());
46 }
47 }
48
49 ttcn_buffer.get_string(ret_val);
50 return ret_val;
51}
52
53RlcmacDlDataBlock dec__RlcmacDlDataBlock(const OCTETSTRING& stream)
54{
55 RlcmacDlDataBlock ret_val;
56 TTCN_Buffer ttcn_buffer(stream);
57 int num_llc_blocks = 0;
58
59 /* use automatic/generated decoder for header */
60 ret_val.mac__hdr().decode(DlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
61
62 /* optional extension octets, containing LI+M+E of Llc blocks */
63 if (ret_val.mac__hdr().hdr__ext().e() == false) {
64 /* extension octet follows, i.e. optional Llc length octets */
65 while (1) {
66 /* decode one more extension octet with LlcBlocHdr inside */
67 LlcBlock lb;
68 lb.hdr().decode(LlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
69 ret_val.blocks()[num_llc_blocks++] = lb;
70
71 /* if E == '1'B, we can proceed further */
72 if (lb.hdr().e() == true)
73 break;
74 }
75 }
76
77 /* RLC blocks at end */
78 if (ret_val.mac__hdr().hdr__ext().e() == true) {
79 LlcBlock lb;
80 unsigned int length = ttcn_buffer.get_read_len();
81 /* LI not present: The Upper Layer PDU that starts with the current RLC data block either
82 * fills the current RLC data block precisely or continues in the following in-sequence RLC
83 * data block */
84 lb.payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
85 ttcn_buffer.increase_pos(length);
86 ret_val.blocks()[0] = lb;
87 } else {
88 if (ret_val.blocks().is_bound()) {
89 for (int i = 0; i < ret_val.blocks().size_of(); i++) {
90 unsigned int length = ret_val.blocks()[i].hdr().length__ind();
91 if (length > ttcn_buffer.get_read_len())
92 length = ttcn_buffer.get_read_len();
93 ret_val.blocks()[i].payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
94 ttcn_buffer.increase_pos(length);
95 }
96 }
97 }
98
99 return ret_val;
100}
101
102
103OCTETSTRING enc__RlcmacUlDataBlock(const RlcmacUlDataBlock& si)
104{
105 RlcmacUlDataBlock in = si;
106 OCTETSTRING ret_val;
107 TTCN_Buffer ttcn_buffer;
108 int i;
109
110 /* Fix 'e' bit of initial header based on following blocks */
Harald Welte244cd8a2017-08-26 09:25:20 +0200111 if (!in.blocks().is_bound() ||
112 (in.blocks().size_of() == 1 && !in.blocks()[0].hdr().is_bound()))
Harald Welte43e060a2017-07-30 22:38:03 +0200113 in.mac__hdr().e() = true;
114 else
115 in.mac__hdr().e() = false;
116
117 /* Fix other presence indications */
Harald Welte2072ab62017-07-31 18:33:35 +0200118 in.mac__hdr().tlli__ind() = in.tlli().is_bound() && in.tlli() != OMIT_VALUE;
119 in.mac__hdr().pfi__ind() = in.pfi().is_bound() && in.pfi() != OMIT_VALUE;
Harald Welte43e060a2017-07-30 22:38:03 +0200120
121 /* use automatic/generated decoder for header */
122 in.mac__hdr().encode(UlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
123
124 /* Add LI octets, if any */
125 if (in.blocks().is_bound() &&
126 (in.blocks().size_of() != 1 || in.blocks()[0].hdr().is_bound())) {
127 /* first write LI octets */
128 for (i = 0; i < in.blocks().size_of(); i++) {
129 /* fix the 'E' bit in case it is not clear */
130 if (i < in.blocks().size_of()-1)
131 in.blocks()[i].hdr().e() = false;
132 else
133 in.blocks()[i].hdr().e() = true;
134 in.blocks()[i].hdr().encode(LlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
135 }
136 }
137
138 if (in.mac__hdr().tlli__ind()) {
139 /* FIXME */
140 //in.tlli().encode(GSM__Types::GprsTlli_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
141 INTEGER t = in.tlli();
142 unsigned int tmp = t.get_long_long_val();
143 ttcn_buffer.put_c(tmp >> 24);
144 ttcn_buffer.put_c(tmp >> 16);
145 ttcn_buffer.put_c(tmp >> 8);
146 ttcn_buffer.put_c(tmp);
147 }
148
149 if (in.mac__hdr().pfi__ind()) {
150 in.pfi().encode(RlcmacUlDataBlock_pfi_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
151 }
152
153 if (in.blocks().is_bound()) {
154 for (i = 0; i < in.blocks().size_of(); i++) {
155 if (!in.blocks()[i].is_bound())
156 continue;
157 ttcn_buffer.put_string(in.blocks()[i].payload());
158 }
159 }
160
161 ttcn_buffer.get_string(ret_val);
162 return ret_val;
163}
164
165RlcmacUlDataBlock dec__RlcmacUlDataBlock(const OCTETSTRING& stream)
166{
167 RlcmacUlDataBlock ret_val;
168 TTCN_Buffer ttcn_buffer(stream);
169 int num_llc_blocks = 0;
170
171 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
172 TTCN_Logger::log_event_str("==================================\n"
173 "dec_RlcmacUlDataBlock(): Stream before decoding: ");
174 stream.log();
175 TTCN_Logger::end_event();
176
177 /* use automatic/generated decoder for header */
178 ret_val.mac__hdr().decode(UlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
179
180 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
181 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): Stream after decoding hdr: ");
182 ttcn_buffer.log();
183 TTCN_Logger::end_event();
184 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
185 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): ret_val after decoding hdr: ");
186 ret_val.log();
187 TTCN_Logger::end_event();
188
189 /* Manually decoder remainder of ttcn_buffer, containing optional header octets,
190 * optional tlli, optional pfi and LLC Blocks */
191
192 /* optional extension octets, containing LI+M+E of Llc blocks */
193 if (ret_val.mac__hdr().e() == false) {
194 /* extension octet follows, i.e. optional Llc length octets */
195 while (1) {
196 /* decode one more extension octet with LlcBlocHdr inside */
197 LlcBlock lb;
198 lb.hdr().decode(LlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
199 ret_val.blocks()[num_llc_blocks++] = lb;
200
201 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
202 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): Stream after decoding ExtOct: ");
203 ttcn_buffer.log();
204 TTCN_Logger::end_event();
205 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
206 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): ret_val after decoding ExtOct: ");
207 ret_val.log();
208 TTCN_Logger::end_event();
209
210 /* if E == '1'B, we can proceed further */
211 if (lb.hdr().e() == true)
212 break;
213 }
214 }
215
216 /* parse optional TLLI */
217 if (ret_val.mac__hdr().tlli__ind()) {
218 /* FIXME: Why is this not working ?!? */
219 //ret_val.tlli().decode(GSM__Types::GprsTlli_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
220 const unsigned char *cur = ttcn_buffer.get_read_data();
221 unsigned int tmp = cur[0] << 24 | cur[1] << 16 | cur[2] << 8 | cur[3];
222 INTEGER t;
223 t.set_long_long_val(tmp);
224 ret_val.tlli() = t;
225 ttcn_buffer.increase_pos(4);
226 }
227 /* parse optional PFI */
228 if (ret_val.mac__hdr().pfi__ind()) {
229 ret_val.pfi().decode(RlcmacUlDataBlock_pfi_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
230 }
231
232 /* RLC blocks at end */
233 if (ret_val.mac__hdr().e() == true) {
234 LlcBlock lb;
235 unsigned int length = ttcn_buffer.get_read_len();
236 /* LI not present: The Upper Layer PDU that starts with the current RLC data block either
237 * fills the current RLC data block precisely or continues in the following in-sequence RLC
238 * data block */
239 lb.payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
240 ttcn_buffer.increase_pos(length);
241 ret_val.blocks()[0] = lb;
242 } else {
243 if (ret_val.blocks().is_bound()) {
244 for (int i = 0; i < ret_val.blocks().size_of(); i++) {
245 unsigned int length = ret_val.blocks()[i].hdr().length__ind();
246 if (length > ttcn_buffer.get_read_len())
247 length = ttcn_buffer.get_read_len();
248 ret_val.blocks()[i].payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
249 ttcn_buffer.increase_pos(length);
250 }
251 }
252 }
253
254 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
255 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): Stream before return: ");
256 ttcn_buffer.log();
257 TTCN_Logger::end_event();
258 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
259 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): ret_val before return: ");
260 ret_val.log();
261 TTCN_Logger::end_event();
262
263 return ret_val;
264}
265
Harald Welte78a1af62017-07-31 17:33:56 +0200266OCTETSTRING enc__RlcmacUlBlock(const RlcmacUlBlock& si)
267{
268 if (si.ischosen(RlcmacUlBlock::ALT_data))
269 return enc__RlcmacUlDataBlock(si.data());
270 else
271 return enc__RlcmacUlCtrlBlock(si.ctrl());
272}
273
274OCTETSTRING enc__RlcmacDlBlock(const RlcmacDlBlock& si)
275{
276 if (si.ischosen(RlcmacDlBlock::ALT_data))
277 return enc__RlcmacDlDataBlock(si.data());
278 else
279 return enc__RlcmacDlCtrlBlock(si.ctrl());
280}
281
282
283RlcmacUlBlock dec__RlcmacUlBlock(const OCTETSTRING& stream)
284{
285 RlcmacUlBlock ret_val;
286 unsigned char pt = stream[0].get_octet() >> 6;
287
288 if (pt == MacPayloadType::MAC__PT__RLC__DATA)
289 ret_val.data() = dec__RlcmacUlDataBlock(stream);
290 else
291 ret_val.ctrl() = dec__RlcmacUlCtrlBlock(stream);
292
293 return ret_val;
294}
295
296RlcmacDlBlock dec__RlcmacDlBlock(const OCTETSTRING& stream)
297{
298 RlcmacDlBlock ret_val;
299 unsigned char pt = stream[0].get_octet() >> 6;
300
301 if (pt == MacPayloadType::MAC__PT__RLC__DATA)
302 ret_val.data() = dec__RlcmacDlDataBlock(stream);
303 else
304 ret_val.ctrl() = dec__RlcmacDlCtrlBlock(stream);
305
306 return ret_val;
307}
308
Harald Welte43e060a2017-07-30 22:38:03 +0200309
310} // namespace