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