blob: a19f6451437396b113b3d3cf9fd3ff89360cd607 [file] [log] [blame]
Philipp22611be2016-08-10 12:08:03 +02001/* GPRS SNDCP XID field encoding/decoding as per 3GPP TS 44.065 */
2
3/* (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
4 * All Rights Reserved
5 *
6 * Author: Philipp Maier
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Affero General Public License for more details.
17 *
18 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#include <stdio.h>
23#include <string.h>
24#include <stdint.h>
25#include <math.h>
26#include <errno.h>
27
28#include <osmocom/core/utils.h>
29#include <osmocom/core/msgb.h>
30#include <osmocom/core/linuxlist.h>
31#include <osmocom/core/talloc.h>
32#include <osmocom/gsm/tlv.h>
33
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020034#include <osmocom/sgsn/debug.h>
35#include <osmocom/sgsn/gprs_llc.h>
36#include <osmocom/sgsn/sgsn.h>
37#include <osmocom/sgsn/gprs_sndcp_xid.h>
Philipp22611be2016-08-10 12:08:03 +020038
39/* When the propose bit in an SNDCP-XID compression field is set to zero,
40 * the algorithm identifier is stripped. The algoritm parameters are specific
41 * for each algorithms. The following struct is used to pass the information
42 * about the referenced algorithm to the parser. */
43struct entity_algo_table {
44 unsigned int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */
Stefan Sperlingc5721542018-11-07 16:33:39 +010045 union gprs_sndcp_comp_algo algo;
46 enum gprs_sndcp_xid_param_types compclass;
Philipp22611be2016-08-10 12:08:03 +020047};
48
49/* FUNCTIONS RELATED TO SNDCP-XID ENCODING */
50
51/* Encode applicable sapis (works the same in all three compression schemes) */
52static int encode_pcomp_applicable_sapis(uint8_t *dst,
53 const uint8_t *nsapis,
54 uint8_t nsapis_len)
55{
56 /* NOTE: Buffer *dst needs offer at 2 bytes
57 * of space to store the generation results */
58
59 uint16_t blob;
60 uint8_t nsapi;
61 int i;
62
63 /* Bail if number of possible nsapis exceeds valid range
64 * (Only 11 nsapis possible for PDP-Contexts) */
65 OSMO_ASSERT(nsapis_len <= 11);
66
67 /* Encode applicable SAPIs */
68 blob = 0;
69 for (i = 0; i < nsapis_len; i++) {
70 nsapi = nsapis[i];
71 /* Only NSAPI 5 to 15 are applicable for user traffic (PDP-
72 * contexts). Only for these NSAPIs SNDCP-XID parameters
73 * can apply. See also 3GPP TS 44.065, 5.1 Service primitives */
74 OSMO_ASSERT(nsapi >= 5 && nsapi <= 15);
75 blob |= (1 << nsapi);
76 }
77
78 /* Store result */
79 *dst = (blob >> 8) & 0xFF;
80 dst++;
81 *dst = blob & 0xFF;
82
83 return 2;
84}
85
86/* Encode rfc1144 parameter field
87 * (see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */
88static int encode_pcomp_rfc1144_params(uint8_t *dst, unsigned int dst_maxlen,
89 const struct
90 gprs_sndcp_pcomp_rfc1144_params *params)
91{
92 /* NOTE: Buffer *dst should offer at least 3 bytes
93 * of space to store the generation results */
94
95 int dst_counter = 0;
96 int rc;
97
98 OSMO_ASSERT(dst_maxlen >= 3);
99
100 /* Zero out buffer */
101 memset(dst, 0, dst_maxlen);
102
103 /* Encode applicable SAPIs */
104 rc = encode_pcomp_applicable_sapis(dst, params->nsapi,
105 params->nsapi_len);
106 dst += rc;
107 dst_counter += rc;
108
109 /* Encode s01 (see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */
110 OSMO_ASSERT(params->s01 >= 0);
111 OSMO_ASSERT(params->s01 <= 255);
112 *dst = params->s01;
113 dst++;
114 dst_counter++;
115
116 /* Return generated length */
117 return dst_counter;
118}
119
120/*
121 * Encode rfc2507 parameter field
122 * (see also: 3GPP TS 44.065, 6.5.3.1, Table 6)
123 */
124static int encode_pcomp_rfc2507_params(uint8_t *dst, unsigned int dst_maxlen,
125 const struct
126 gprs_sndcp_pcomp_rfc2507_params *params)
127{
128 /* NOTE: Buffer *dst should offer at least 3 bytes
129 * of space to store the generation results */
130
131 int dst_counter = 0;
132 int rc;
133
134 OSMO_ASSERT(dst_maxlen >= 9);
135
136 /* Zero out buffer */
137 memset(dst, 0, dst_maxlen);
138
139 /* Encode applicable SAPIs */
140 rc = encode_pcomp_applicable_sapis(dst, params->nsapi,
141 params->nsapi_len);
142 dst += rc;
143 dst_counter += rc;
144
145 /* Encode F_MAX_PERIOD (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */
146 OSMO_ASSERT(params->f_max_period >= 1);
147 OSMO_ASSERT(params->f_max_period <= 65535);
148 *dst = (params->f_max_period >> 8) & 0xFF;
149 dst++;
150 dst_counter++;
151 *dst = (params->f_max_period) & 0xFF;
152 dst++;
153 dst_counter++;
154
155 /* Encode F_MAX_TIME (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */
156 OSMO_ASSERT(params->f_max_time >= 1);
157 OSMO_ASSERT(params->f_max_time <= 255);
158 *dst = params->f_max_time;
159 dst++;
160 dst_counter++;
161
162 /* Encode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */
163 OSMO_ASSERT(params->max_header >= 60);
164 OSMO_ASSERT(params->max_header <= 255);
165 *dst = params->max_header;
166 dst++;
167 dst_counter++;
168
169 /* Encode TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */
170 OSMO_ASSERT(params->tcp_space >= 3);
171 OSMO_ASSERT(params->tcp_space <= 255);
172 *dst = params->tcp_space;
173 dst++;
174 dst_counter++;
175
176 /* Encode NON_TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */
177 OSMO_ASSERT(params->non_tcp_space >= 3);
178 OSMO_ASSERT(params->non_tcp_space <= 65535);
179 *dst = (params->non_tcp_space >> 8) & 0xFF;
180 dst++;
181 dst_counter++;
182 *dst = (params->non_tcp_space) & 0xFF;
183 dst++;
184 dst_counter++;
185
186 /* Return generated length */
187 return dst_counter;
188}
189
190/* Encode ROHC parameter field
191 * (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */
192static int encode_pcomp_rohc_params(uint8_t *dst, unsigned int dst_maxlen,
193 const struct gprs_sndcp_pcomp_rohc_params
194 *params)
195{
196 /* NOTE: Buffer *dst should offer at least 36
197 * (2 * 16 Profiles + 2 * 3 Parameter) bytes
198 * of memory space to store generation results */
199
200 int i;
201 int dst_counter = 0;
202 int rc;
203
204 OSMO_ASSERT(dst_maxlen >= 38);
205
206 /* Bail if number of ROHC profiles exceeds limit
207 * (ROHC supports only a maximum of 16 different profiles) */
Philipp22611be2016-08-10 12:08:03 +0200208 OSMO_ASSERT(params->profile_len <= 16);
209
210 /* Zero out buffer */
211 memset(dst, 0, dst_maxlen);
212
213 /* Encode applicable SAPIs */
214 rc = encode_pcomp_applicable_sapis(dst, params->nsapi,
215 params->nsapi_len);
216 dst += rc;
217 dst_counter += rc;
218
219 /* Encode MAX_CID (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */
220 OSMO_ASSERT(params->max_cid >= 0);
221 OSMO_ASSERT(params->max_cid <= 16383);
222 *dst = (params->max_cid >> 8) & 0xFF;
223 dst++;
224 *dst = params->max_cid & 0xFF;
225 dst++;
226 dst_counter += 2;
227
228 /* Encode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */
229 OSMO_ASSERT(params->max_header >= 60);
230 OSMO_ASSERT(params->max_header <= 255);
231 *dst = (params->max_header >> 8) & 0xFF;
232 dst++;
233 *dst = params->max_header & 0xFF;
234 dst++;
235 dst_counter += 2;
236
237 /* Encode ROHC Profiles (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */
238 for (i = 0; i < params->profile_len; i++) {
239 *dst = (params->profile[i] >> 8) & 0xFF;
240 dst++;
241 *dst = params->profile[i] & 0xFF;
242 dst++;
243 dst_counter += 2;
244 }
245
246 /* Return generated length */
247 return dst_counter;
248}
249
250/* Encode V.42bis parameter field
251 * (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */
252static int encode_dcomp_v42bis_params(uint8_t *dst, unsigned int dst_maxlen,
253 const struct
254 gprs_sndcp_dcomp_v42bis_params *params)
255{
256 /* NOTE: Buffer *dst should offer at least 6 bytes
257 * of space to store the generation results */
258
259 int dst_counter = 0;
260 int rc;
261
262 OSMO_ASSERT(dst_maxlen >= 6);
263
264 /* Zero out buffer */
265 memset(dst, 0, dst_maxlen);
266
267 /* Encode applicable SAPIs */
268 rc = encode_pcomp_applicable_sapis(dst, params->nsapi,
269 params->nsapi_len);
270 dst += rc;
271 dst_counter += rc;
272
273 /* Encode P0 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */
274 OSMO_ASSERT(params->p0 >= 0);
275 OSMO_ASSERT(params->p0 <= 3);
276 *dst = params->p0 & 0x03;
277 dst++;
278 dst_counter++;
279
280 /* Encode P1 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */
281 OSMO_ASSERT(params->p1 >= 512);
282 OSMO_ASSERT(params->p1 <= 65535);
283 *dst = (params->p1 >> 8) & 0xFF;
284 dst++;
285 *dst = params->p1 & 0xFF;
286 dst++;
287 dst_counter += 2;
288
289 /* Encode P2 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */
290 OSMO_ASSERT(params->p2 >= 6);
291 OSMO_ASSERT(params->p2 <= 250);
292 *dst = params->p2;
293 dst++;
294 dst_counter++;
295
296 /* Return generated length */
297 return dst_counter;
298}
299
300/* Encode V44 parameter field
301 * (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */
302static int encode_dcomp_v44_params(uint8_t *dst, unsigned int dst_maxlen,
303 const struct gprs_sndcp_dcomp_v44_params
304 *params)
305{
306 /* NOTE: Buffer *dst should offer at least 12 bytes
307 * of space to store the generation results */
308
309 int dst_counter = 0;
310 int rc;
311
312 OSMO_ASSERT(dst_maxlen >= 12);
313
314 /* Zero out buffer */
315 memset(dst, 0, dst_maxlen);
316
317 /* Encode applicable SAPIs */
318 rc = encode_pcomp_applicable_sapis(dst, params->nsapi,
319 params->nsapi_len);
320 dst += rc;
321 dst_counter += rc;
322
323 /* Encode C0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */
324 OSMO_ASSERT(params->c0 == 0x80 || params->c0 == 0xC0);
325 *dst = params->c0 & 0xC0;
326 dst++;
327 dst_counter++;
328
329 /* Encode P0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */
330 OSMO_ASSERT(params->p0 >= 0);
331 OSMO_ASSERT(params->p0 <= 3);
332 *dst = params->p0 & 0x03;
333 dst++;
334 dst_counter++;
335
336 /* Encode P1T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */
337 OSMO_ASSERT(params->p1t >= 256);
338 OSMO_ASSERT(params->p1t <= 65535);
339 *dst = (params->p1t >> 8) & 0xFF;
340 dst++;
341 *dst = params->p1t & 0xFF;
342 dst++;
343 dst_counter += 2;
344
345 /* Encode P1R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */
346 OSMO_ASSERT(params->p1r >= 256);
347 OSMO_ASSERT(params->p1r <= 65535);
348 *dst = (params->p1r >> 8) & 0xFF;
349 dst++;
350 *dst = params->p1r & 0xFF;
351 dst++;
352 dst_counter += 2;
353
354 /* Encode P3T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */
355 OSMO_ASSERT(params->p3t >= 0);
356 OSMO_ASSERT(params->p3t <= 65535);
357 OSMO_ASSERT(params->p3t >= 2 * params->p1t);
358 *dst = (params->p3t >> 8) & 0xFF;
359 dst++;
360 *dst = params->p3t & 0xFF;
361 dst++;
362 dst_counter += 2;
363
364 /* Encode P3R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */
365 OSMO_ASSERT(params->p3r >= 0);
366 OSMO_ASSERT(params->p3r <= 65535);
367 OSMO_ASSERT(params->p3r >= 2 * params->p1r);
368 *dst = (params->p3r >> 8) & 0xFF;
369 dst++;
370 *dst = params->p3r & 0xFF;
371 dst++;
372 dst_counter += 2;
373
374 /* Return generated length */
375 return dst_counter;
376}
377
378/* Encode data or protocol control information compression field
379 * (see also: 3GPP TS 44.065, 6.6.1.1, Figure 9 and
380 * 3GPP TS 44.065, 6.5.1.1, Figure 7) */
381static int encode_comp_field(uint8_t *dst, unsigned int dst_maxlen,
382 const struct gprs_sndcp_comp_field *comp_field)
383{
384 int dst_counter = 0;
385 int len;
386 int expected_length;
387 int i;
Stefan Sperlingc5721542018-11-07 16:33:39 +0100388 enum gprs_sndcp_xid_param_types compclass;
Philipp22611be2016-08-10 12:08:03 +0200389
390 uint8_t payload_bytes[256];
391 int payload_bytes_len = -1;
392
393 /* If possible, try do encode payload bytes first */
394 if (comp_field->rfc1144_params) {
395 payload_bytes_len =
396 encode_pcomp_rfc1144_params(payload_bytes,
397 sizeof(payload_bytes),
398 comp_field->rfc1144_params);
399 } else if (comp_field->rfc2507_params) {
400 payload_bytes_len =
401 encode_pcomp_rfc2507_params(payload_bytes,
402 sizeof(payload_bytes),
403 comp_field->rfc2507_params);
404 } else if (comp_field->rohc_params) {
405 payload_bytes_len =
406 encode_pcomp_rohc_params(payload_bytes,
407 sizeof(payload_bytes),
408 comp_field->rohc_params);
409 } else if (comp_field->v42bis_params) {
410 payload_bytes_len =
411 encode_dcomp_v42bis_params(payload_bytes,
412 sizeof(payload_bytes),
413 comp_field->v42bis_params);
414 } else if (comp_field->v44_params) {
415 payload_bytes_len =
416 encode_dcomp_v44_params(payload_bytes,
417 sizeof(payload_bytes),
418 comp_field->v44_params);
419 } else
420 OSMO_ASSERT(false);
421
422 /* Bail immediately if payload byte generation failed */
423 OSMO_ASSERT(payload_bytes_len >= 0);
424
425 /* Bail if comp_len is out of bounds */
426 OSMO_ASSERT(comp_field->comp_len <= sizeof(comp_field->comp));
427
428 /* Calculate length field of the data block */
429 if (comp_field->p) {
430 len =
431 payload_bytes_len +
432 ceil((double)(comp_field->comp_len) / 2.0);
433 expected_length = len + 3;
434 } else {
435 len = payload_bytes_len;
436 expected_length = len + 2;
437 }
438
439 /* Bail immediately if no sufficient memory space is supplied */
440 OSMO_ASSERT(dst_maxlen >= expected_length);
441
442 /* Check if the entity number is within bounds */
443 OSMO_ASSERT(comp_field->entity <= 0x1f);
444
445 /* Check if the algorithm number is within bounds */
Stefan Sperlingc5721542018-11-07 16:33:39 +0100446 compclass = gprs_sndcp_get_compression_class(comp_field);
447 switch (compclass) {
448 case SNDCP_XID_PROTOCOL_COMPRESSION:
449 OSMO_ASSERT(comp_field->algo.pcomp >= 0 && comp_field->algo.pcomp <= 0x1f);
450 break;
451 case SNDCP_XID_DATA_COMPRESSION:
452 OSMO_ASSERT(comp_field->algo.dcomp >= 0 && comp_field->algo.dcomp <= 0x1f);
453 break;
454 default:
455 OSMO_ASSERT(false);
456 }
Philipp22611be2016-08-10 12:08:03 +0200457
458 /* Zero out buffer */
459 memset(dst, 0, dst_maxlen);
460
461 /* Encode Propose bit */
462 if (comp_field->p)
463 *dst |= (1 << 7);
464
465 /* Encode entity number */
466 *dst |= comp_field->entity & 0x1F;
467 dst++;
468 dst_counter++;
469
470 /* Encode algorithm number */
471 if (comp_field->p) {
Stefan Sperlingc5721542018-11-07 16:33:39 +0100472 if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION)
473 *dst |= comp_field->algo.pcomp & 0x1F;
474 else
475 *dst |= comp_field->algo.dcomp & 0x1F;
Philipp22611be2016-08-10 12:08:03 +0200476 dst++;
477 dst_counter++;
478 }
479
480 /* Encode length field */
481 *dst |= len & 0xFF;
482 dst++;
483 dst_counter++;
484
485 /* Encode PCOMP/DCOMP values */
486 if (comp_field->p) {
487 for (i = 0; i < comp_field->comp_len; i++) {
488 /* Check if submitted PCOMP/DCOMP
489 values are within bounds */
Philippae9beda2016-09-28 15:10:14 +0200490 if (comp_field->comp[i] > 0x0F)
Philipp22611be2016-08-10 12:08:03 +0200491 return -EINVAL;
492
493 if (i & 1) {
494 *dst |= comp_field->comp[i] & 0x0F;
495 dst++;
496 dst_counter++;
497 } else
498 *dst |= (comp_field->comp[i] << 4) & 0xF0;
499 }
500
501 if (i & 1) {
502 dst++;
503 dst_counter++;
504 }
505 }
506
507 /* Append payload bytes */
508 memcpy(dst, payload_bytes, payload_bytes_len);
509 dst_counter += payload_bytes_len;
510
511 /* Return generated length */
512 return dst_counter;
513}
514
515/* Find out to which compression class the specified comp-field belongs
516 * (header compression or data compression?) */
Stefan Sperlingc5721542018-11-07 16:33:39 +0100517enum gprs_sndcp_xid_param_types gprs_sndcp_get_compression_class(const struct gprs_sndcp_comp_field
Philipp22611be2016-08-10 12:08:03 +0200518 *comp_field)
519{
520 OSMO_ASSERT(comp_field);
521
522 if (comp_field->rfc1144_params)
523 return SNDCP_XID_PROTOCOL_COMPRESSION;
524 else if (comp_field->rfc2507_params)
525 return SNDCP_XID_PROTOCOL_COMPRESSION;
526 else if (comp_field->rohc_params)
527 return SNDCP_XID_PROTOCOL_COMPRESSION;
528 else if (comp_field->v42bis_params)
529 return SNDCP_XID_DATA_COMPRESSION;
530 else if (comp_field->v44_params)
531 return SNDCP_XID_DATA_COMPRESSION;
532 else
Stefan Sperlingc5721542018-11-07 16:33:39 +0100533 return SNDCP_XID_INVALID_COMPRESSION;
Philipp22611be2016-08-10 12:08:03 +0200534}
535
536/* Convert all compression fields to bytstreams */
537static int gprs_sndcp_pack_fields(const struct llist_head *comp_fields,
538 uint8_t *dst,
539 unsigned int dst_maxlen, int class)
540{
541 struct gprs_sndcp_comp_field *comp_field;
542 int byte_counter = 0;
543 int rc;
544
545 llist_for_each_entry_reverse(comp_field, comp_fields, list) {
546 if (class == gprs_sndcp_get_compression_class(comp_field)) {
547 rc = encode_comp_field(dst + byte_counter,
548 dst_maxlen - byte_counter,
549 comp_field);
550
551 /* When input data is correct, there is
552 * no reason for the encoder to fail! */
553 OSMO_ASSERT(rc >= 0);
554
555 byte_counter += rc;
556 }
557 }
558
559 /* Return generated length */
560 return byte_counter;
561}
562
563/* Transform a list with compression fields into an SNDCP-XID message (dst) */
564int gprs_sndcp_compile_xid(uint8_t *dst, unsigned int dst_maxlen,
Philippdb142dc2016-12-22 14:15:20 +0100565 const struct llist_head *comp_fields, int version)
Philipp22611be2016-08-10 12:08:03 +0200566{
567 int rc;
568 int byte_counter = 0;
569 uint8_t comp_bytes[512];
Philippdb142dc2016-12-22 14:15:20 +0100570 uint8_t xid_version_number[1];
Philipp22611be2016-08-10 12:08:03 +0200571
572 OSMO_ASSERT(comp_fields);
573 OSMO_ASSERT(dst);
574 OSMO_ASSERT(dst_maxlen >= 2 + sizeof(xid_version_number));
575
Philippdb142dc2016-12-22 14:15:20 +0100576 /* Prepend header with version number */
577 if (version >= 0) {
578 xid_version_number[0] = (uint8_t) (version & 0xff);
579 dst =
580 tlv_put(dst, SNDCP_XID_VERSION_NUMBER,
581 sizeof(xid_version_number), xid_version_number);
582 byte_counter += (sizeof(xid_version_number) + 2);
583 }
Philipp22611be2016-08-10 12:08:03 +0200584
Philippdb142dc2016-12-22 14:15:20 +0100585 /* Stop if there is no compression fields supplied */
586 if (llist_empty(comp_fields))
587 return byte_counter;
Philipp22611be2016-08-10 12:08:03 +0200588
589 /* Add data compression fields */
590 rc = gprs_sndcp_pack_fields(comp_fields, comp_bytes,
591 sizeof(comp_bytes),
592 SNDCP_XID_DATA_COMPRESSION);
593 OSMO_ASSERT(rc >= 0);
594
595 if (rc > 0) {
596 dst = tlv_put(dst, SNDCP_XID_DATA_COMPRESSION, rc, comp_bytes);
597 byte_counter += rc + 2;
598 }
599
600 /* Add header compression fields */
601 rc = gprs_sndcp_pack_fields(comp_fields, comp_bytes,
602 sizeof(comp_bytes),
603 SNDCP_XID_PROTOCOL_COMPRESSION);
604 OSMO_ASSERT(rc >= 0);
605
606 if (rc > 0) {
607 dst = tlv_put(dst, SNDCP_XID_PROTOCOL_COMPRESSION, rc,
608 comp_bytes);
609 byte_counter += rc + 2;
610 }
611
612 /* Return generated length */
613 return byte_counter;
614}
615
616/* FUNCTIONS RELATED TO SNDCP-XID DECODING */
617
618/* Decode applicable sapis (works the same in all three compression schemes) */
619static int decode_pcomp_applicable_sapis(uint8_t *nsapis,
620 uint8_t *nsapis_len,
621 const uint8_t *src,
622 unsigned int src_len)
623{
624 uint16_t blob;
625 int i;
626 int nsapi_len = 0;
627
628 /* Exit immediately if no result can be stored */
629 if (!nsapis)
630 return -EINVAL;
631
632 /* Exit immediately if not enough input data is available */
633 if (src_len < 2)
634 return -EINVAL;
635
636 /* Read bitmask */
637 blob = *src;
638 blob = (blob << 8) & 0xFF00;
639 src++;
640 blob |= (*src) & 0xFF;
641 blob = (blob >> 5);
642
643 /* Decode applicable SAPIs */
644 for (i = 0; i < 15; i++) {
645 if ((blob >> i) & 1) {
646 nsapis[nsapi_len] = i + 5;
647 nsapi_len++;
648 }
649 }
650
651 /* Return consumed length */
652 *nsapis_len = nsapi_len;
653 return 2;
654}
655
656/* Decode 16 bit field */
657static int decode_pcomp_16_bit_field(int *value_int, uint16_t * value_uint16,
658 const uint8_t *src,
659 unsigned int src_len,
660 int value_min, int value_max)
661{
662 uint16_t blob;
663
664 /* Reset values to zero (just to be sure) */
665 if (value_int)
666 *value_int = -1;
667 if (value_uint16)
668 *value_uint16 = 0;
669
670 /* Exit if not enough src are available */
671 if (src_len < 2)
672 return -EINVAL;
673
674 /* Decode bit value */
675 blob = *src;
676 blob = (blob << 8) & 0xFF00;
677 src++;
678 blob |= *src;
679
680 /* Check if parsed value is within bounds */
681 if (blob < value_min)
682 return -EINVAL;
683 if (blob > value_max)
684 return -EINVAL;
685
686 /* Hand back results to the caller */
687 if (value_int)
688 *value_int = blob;
689 if (value_uint16)
690 *value_uint16 = blob;
691
692 /* Return consumed length */
693 return 2;
694}
695
696/* Decode 8 bit field */
697static int decode_pcomp_8_bit_field(int *value_int, uint8_t *value_uint8,
698 const uint8_t *src,
699 unsigned int src_len,
700 int value_min, int value_max)
701{
702 uint8_t blob;
703
704 /* Reset values to invalid (just to be sure) */
705 if (value_int)
706 *value_int = -1;
707 if (value_uint8)
708 *value_uint8 = 0;
709
710 /* Exit if not enough src are available */
711 if (src_len < 1)
712 return -EINVAL;
713
714 /* Decode bit value */
715 blob = *src;
716
717 /* Check if parsed value is within bounds */
718 if (blob < value_min)
719 return -EINVAL;
720 if (blob > value_max)
721 return -EINVAL;
722
723 /* Hand back results to the caller */
724 if (value_int)
725 *value_int = blob;
726 if (value_uint8)
727 *value_uint8 = blob;
728
729 /* Return consumed length */
730 return 1;
731}
732
733/* Decode rfc1144 parameter field see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */
734static int decode_pcomp_rfc1144_params(struct gprs_sndcp_pcomp_rfc1144_params
735 *params, const uint8_t *src,
736 unsigned int src_len)
737{
738 int rc;
739 int byte_counter = 0;
740
741 /* Mark all optional parameters invalid by default */
742 params->s01 = -1;
743
744 /* Decode applicable SAPIs */
745 rc = decode_pcomp_applicable_sapis(params->nsapi, &params->nsapi_len,
746 src, src_len);
747 if (rc > 0) {
748 byte_counter += rc;
749 src += rc;
750 } else
751 return byte_counter;
752
753 /* Decode parameter S0 -1
754 * (see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */
755 rc = decode_pcomp_8_bit_field(&params->s01, NULL, src,
756 src_len - byte_counter, 0, 255);
757 if (rc <= 0)
758 return byte_counter;
759 byte_counter += rc;
760 src += rc;
761
762 /* Return consumed length */
763 return byte_counter;
764}
765
766/* Decode rfc2507 parameter field
767 * (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */
768static int decode_pcomp_rfc2507_params(struct gprs_sndcp_pcomp_rfc2507_params
769 *params, const uint8_t *src,
770 unsigned int src_len)
771{
772 int rc;
773 int byte_counter = 0;
774
775 /* Mark all optional parameters invalid by default */
776 params->f_max_period = -1;
777 params->f_max_time = -1;
778 params->max_header = -1;
779 params->tcp_space = -1;
780 params->non_tcp_space = -1;
781
782 /* Decode applicable SAPIs */
783 rc = decode_pcomp_applicable_sapis(params->nsapi, &params->nsapi_len,
784 src, src_len);
785 if (rc > 0) {
786 byte_counter += rc;
787 src += rc;
788 } else
789 return byte_counter;
790
791 /* Decode F_MAX_PERIOD (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */
792 rc = decode_pcomp_16_bit_field(&params->f_max_period, NULL, src,
793 src_len - byte_counter, 1, 65535);
794 if (rc <= 0)
795 return byte_counter;
796 byte_counter += rc;
797 src += rc;
798
799 /* Decode F_MAX_TIME (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */
800 rc = decode_pcomp_8_bit_field(&params->f_max_time, NULL, src,
801 src_len - byte_counter, 1, 255);
802 if (rc <= 0)
803 return byte_counter;
804 byte_counter += rc;
805 src += rc;
806
807 /* Decode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */
808 rc = decode_pcomp_8_bit_field(&params->max_header, NULL, src,
809 src_len - byte_counter, 60, 255);
810 if (rc <= 0)
811 return byte_counter;
812 byte_counter += rc;
813 src += rc;
814
815 /* Decode TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */
816 rc = decode_pcomp_8_bit_field(&params->tcp_space, NULL, src,
817 src_len - byte_counter, 3, 255);
818 if (rc <= 0)
819 return byte_counter;
820 byte_counter += rc;
821 src += rc;
822
823 /* Decode NON_TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */
824 rc = decode_pcomp_16_bit_field(&params->non_tcp_space, NULL, src,
825 src_len - byte_counter, 3, 65535);
826 if (rc <= 0)
827 return byte_counter;
828 byte_counter += rc;
829 src += rc;
830
831 /* Return consumed length */
832 return byte_counter;
833}
834
835/* Decode ROHC parameter field (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */
836static int decode_pcomp_rohc_params(struct gprs_sndcp_pcomp_rohc_params *params,
837 const uint8_t *src, unsigned int src_len)
838{
839 int rc;
840 int byte_counter = 0;
841 int i;
842
843 /* Mark all optional parameters invalid by default */
844 params->max_cid = -1;
845 params->max_header = -1;
846
847 /* Decode applicable SAPIs */
848 rc = decode_pcomp_applicable_sapis(params->nsapi, &params->nsapi_len,
849 src, src_len);
850 if (rc <= 0)
851 return byte_counter;
852 byte_counter += rc;
853 src += rc;
854
855 /* Decode MAX_CID (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */
856 rc = decode_pcomp_16_bit_field(&params->max_cid, NULL, src,
857 src_len - byte_counter, 0, 16383);
858 if (rc <= 0)
859 return byte_counter;
860 byte_counter += rc;
861 src += rc;
862
863 /* Decode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */
864 rc = decode_pcomp_16_bit_field(&params->max_header, NULL, src,
865 src_len - byte_counter, 60, 255);
866 if (rc <= 0)
867 return byte_counter;
868 byte_counter += rc;
869 src += rc;
870
871 /* Decode Profiles (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */
872 for (i = 0; i < 16; i++) {
873 params->profile_len = 0;
874 rc = decode_pcomp_16_bit_field(NULL, &params->profile[i], src,
875 src_len - byte_counter, 0,
876 65535);
877 if (rc <= 0)
878 return byte_counter;
879 byte_counter += rc;
880 src += rc;
881 params->profile_len = i + 1;
882 }
883
884 /* Return consumed length */
885 return byte_counter;
886}
887
888/* Decode V.42bis parameter field
889 * (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */
890static int decode_dcomp_v42bis_params(struct gprs_sndcp_dcomp_v42bis_params
891 *params, const uint8_t *src,
892 unsigned int src_len)
893{
894 int rc;
895 int byte_counter = 0;
896
897 /* Mark all optional parameters invalid by default */
898 params->p0 = -1;
899 params->p1 = -1;
900 params->p2 = -1;
901
902 /* Decode applicable SAPIs */
903 rc = decode_pcomp_applicable_sapis(params->nsapi, &params->nsapi_len,
904 src, src_len);
905 if (rc > 0) {
906 byte_counter += rc;
907 src += rc;
908 } else
909 return byte_counter;
910
911 /* Decode P0 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */
912 rc = decode_pcomp_8_bit_field(&params->p0, NULL, src,
913 src_len - byte_counter, 0, 3);
914 if (rc <= 0)
915 return byte_counter;
916 byte_counter += rc;
917 src += rc;
918
919 /* Decode P1 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */
920 rc = decode_pcomp_16_bit_field(&params->p1, NULL, src,
921 src_len - byte_counter, 512, 65535);
922 if (rc <= 0)
923 return byte_counter;
924 byte_counter += rc;
925 src += rc;
926
927 /* Decode P2 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */
928 rc = decode_pcomp_8_bit_field(&params->p2, NULL, src,
929 src_len - byte_counter, 6, 250);
930 if (rc <= 0)
931 return byte_counter;
932 byte_counter += rc;
933 src += rc;
934
935 /* Return consumed length */
936 return byte_counter;
937}
938
939/* Decode V44 parameter field (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */
940static int decode_dcomp_v44_params(struct gprs_sndcp_dcomp_v44_params *params,
941 const uint8_t *src, unsigned int src_len)
942{
943 int rc;
944 int byte_counter = 0;
945
946 /* Mark all optional parameters invalid by default */
947 params->c0 = -1;
948 params->p0 = -1;
949 params->p1t = -1;
950 params->p1r = -1;
951 params->p3t = -1;
952 params->p3r = -1;
953
954 /* Decode applicable SAPIs */
955 rc = decode_pcomp_applicable_sapis(params->nsapi, &params->nsapi_len,
956 src, src_len);
957 if (rc > 0) {
958 byte_counter += rc;
959 src += rc;
960 } else
961 return byte_counter;
962
963 /* Decode C0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */
964 rc = decode_pcomp_8_bit_field(&params->c0, NULL, src,
965 src_len - byte_counter, 0, 255);
966 if (rc <= 0)
967 return byte_counter;
968 if ((params->c0 != 0x80) && (params->c0 != 0xC0))
969 return -EINVAL;
970 byte_counter += rc;
971 src += rc;
972
973 /* Decode P0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */
974 rc = decode_pcomp_8_bit_field(&params->p0, NULL, src,
975 src_len - byte_counter, 0, 3);
976 if (rc <= 0)
977 return byte_counter;
978 byte_counter += rc;
979 src += rc;
980
981 /* Decode P1T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */
982 rc = decode_pcomp_16_bit_field(&params->p1t, NULL, src,
983 src_len - byte_counter, 265, 65535);
984 if (rc <= 0)
985 return byte_counter;
986 byte_counter += rc;
987 src += rc;
988
989 /* Decode P1R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */
990 rc = decode_pcomp_16_bit_field(&params->p1r, NULL, src,
991 src_len - byte_counter, 265, 65535);
992 if (rc <= 0)
993 return byte_counter;
994 byte_counter += rc;
995 src += rc;
996
997 /* Decode P3T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */
998 rc = decode_pcomp_16_bit_field(&params->p3t, NULL, src,
999 src_len - byte_counter, 265, 65535);
1000 if (rc <= 0)
1001 return byte_counter;
1002 if (params->p3t < 2 * params->p1t)
1003 return -EINVAL;
1004 byte_counter += rc;
1005 src += rc;
1006
1007 /* Decode P3R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */
1008 rc = decode_pcomp_16_bit_field(&params->p3r, NULL, src,
1009 src_len - byte_counter, 265, 65535);
1010 if (rc <= 0)
1011 return byte_counter;
1012 if (params->p3r < 2 * params->p1r)
1013 return -EINVAL;
1014 byte_counter += rc;
1015 src += rc;
1016
1017 /* Return consumed length */
1018 return byte_counter;
1019}
1020
Stefan Sperlingc5721542018-11-07 16:33:39 +01001021/* Lookup protocol compression algorithm identfier by entity ID */
1022static enum gprs_sndcp_hdr_comp_algo lookup_algorithm_identifier_pcomp(int entity,
1023 const struct entity_algo_table *lt,
1024 unsigned int lt_len)
Philipp22611be2016-08-10 12:08:03 +02001025{
1026 int i;
1027
1028 if (!lt)
1029 return -1;
1030
1031 for (i = 0; i < lt_len; i++) {
1032 if ((lt[i].entity == entity)
Stefan Sperlingc5721542018-11-07 16:33:39 +01001033 && (lt[i].compclass == SNDCP_XID_PROTOCOL_COMPRESSION))
1034 return lt[i].algo.pcomp;
Philipp22611be2016-08-10 12:08:03 +02001035 }
1036
Stefan Sperlingc5721542018-11-07 16:33:39 +01001037 return SNDCP_XID_INVALID_COMPRESSION;
1038}
1039
1040/* Lookup a data compression algorithm identfier by entity ID */
1041static enum gprs_sndcp_data_comp_algo lookup_algorithm_identifier_dcomp(int entity,
1042 const struct entity_algo_table *lt,
1043 unsigned int lt_len)
1044{
1045 int i;
1046
1047 if (!lt)
1048 return -1;
1049
1050 for (i = 0; i < lt_len; i++) {
1051 if ((lt[i].entity == entity)
1052 && (lt[i].compclass == SNDCP_XID_DATA_COMPRESSION))
1053 return lt[i].algo.dcomp;
1054 }
1055
1056 return SNDCP_XID_INVALID_COMPRESSION;
Philipp22611be2016-08-10 12:08:03 +02001057}
1058
1059/* Helper function for decode_comp_field(), decodes
1060 * numeric pcomp/dcomp values */
1061static int decode_comp_values(struct gprs_sndcp_comp_field *comp_field,
Stefan Sperlingc5721542018-11-07 16:33:39 +01001062 const uint8_t *src, enum gprs_sndcp_xid_param_types compclass)
Philipp22611be2016-08-10 12:08:03 +02001063{
1064 int src_counter = 0;
1065 int i;
1066
1067 if (comp_field->p) {
1068 /* Determine the number of expected PCOMP/DCOMP values */
Stefan Sperlingc5721542018-11-07 16:33:39 +01001069 switch (compclass) {
1070 case SNDCP_XID_PROTOCOL_COMPRESSION:
Philipp22611be2016-08-10 12:08:03 +02001071 /* For protocol compression */
Stefan Sperlingc5721542018-11-07 16:33:39 +01001072 switch (comp_field->algo.pcomp) {
Philipp22611be2016-08-10 12:08:03 +02001073 case RFC_1144:
1074 comp_field->comp_len = RFC1144_PCOMP_NUM;
1075 break;
1076 case RFC_2507:
1077 comp_field->comp_len = RFC2507_PCOMP_NUM;
1078 break;
1079 case ROHC:
1080 comp_field->comp_len = ROHC_PCOMP_NUM;
1081 break;
1082
1083 /* Exit if the algorithem type encodes
1084 something unknown / unspecified */
1085 default:
1086 return -EINVAL;
1087 }
Stefan Sperlingc5721542018-11-07 16:33:39 +01001088 break;
1089 case SNDCP_XID_DATA_COMPRESSION:
Philipp22611be2016-08-10 12:08:03 +02001090 /* For data compression */
Stefan Sperlingc5721542018-11-07 16:33:39 +01001091 switch (comp_field->algo.dcomp) {
Philipp22611be2016-08-10 12:08:03 +02001092 case V42BIS:
1093 comp_field->comp_len = V42BIS_DCOMP_NUM;
1094 break;
1095 case V44:
1096 comp_field->comp_len = V44_DCOMP_NUM;
1097 break;
1098
1099 /* Exit if the algorithem type encodes
1100 something unknown / unspecified */
1101 default:
1102 return -EINVAL;
1103 }
Stefan Sperlingc5721542018-11-07 16:33:39 +01001104 break;
1105 default:
1106 return -EINVAL;
Philipp22611be2016-08-10 12:08:03 +02001107 }
1108
1109 for (i = 0; i < comp_field->comp_len; i++) {
1110 if (i & 1) {
1111 comp_field->comp[i] = (*src) & 0x0F;
1112 src++;
1113 src_counter++;
1114 } else
1115 comp_field->comp[i] = ((*src) >> 4) & 0x0F;
1116 }
1117
1118 if (i & 1) {
1119 src++;
1120 src_counter++;
1121 }
1122 }
1123
1124 return src_counter;
1125}
1126
1127/* Helper function for decode_comp_field(), decodes the parameters
1128 * which are protocol compression specific */
1129static int decode_pcomp_params(struct gprs_sndcp_comp_field *comp_field,
1130 const uint8_t *src, int src_len)
1131{
1132 int rc;
1133
Stefan Sperlingc5721542018-11-07 16:33:39 +01001134 switch (comp_field->algo.pcomp) {
Philipp22611be2016-08-10 12:08:03 +02001135 case RFC_1144:
1136 comp_field->rfc1144_params = talloc_zero(comp_field, struct
1137 gprs_sndcp_pcomp_rfc1144_params);
1138 rc = decode_pcomp_rfc1144_params(comp_field->rfc1144_params,
1139 src, src_len);
1140 if (rc < 0)
1141 talloc_free(comp_field->rfc1144_params);
1142 break;
1143 case RFC_2507:
1144 comp_field->rfc2507_params = talloc_zero(comp_field, struct
1145 gprs_sndcp_pcomp_rfc2507_params);
1146 rc = decode_pcomp_rfc2507_params(comp_field->rfc2507_params,
1147 src, src_len);
1148 if (rc < 0)
1149 talloc_free(comp_field->rfc1144_params);
1150 break;
1151 case ROHC:
1152 comp_field->rohc_params = talloc_zero(comp_field, struct
1153 gprs_sndcp_pcomp_rohc_params);
1154 rc = decode_pcomp_rohc_params(comp_field->rohc_params, src,
1155 src_len);
1156 if (rc < 0)
1157 talloc_free(comp_field->rohc_params);
1158 break;
1159
1160 /* If no suitable decoder is detected,
1161 leave the remaining bytes undecoded */
1162 default:
1163 rc = src_len;
1164 }
1165
1166 if (rc < 0) {
1167 comp_field->rfc1144_params = NULL;
1168 comp_field->rfc2507_params = NULL;
1169 comp_field->rohc_params = NULL;
1170 }
1171
1172 return rc;
1173}
1174
1175/* Helper function for decode_comp_field(), decodes the parameters
1176 * which are data compression specific */
1177static int decode_dcomp_params(struct gprs_sndcp_comp_field *comp_field,
1178 const uint8_t *src, int src_len)
1179{
1180 int rc;
1181
Stefan Sperlingc5721542018-11-07 16:33:39 +01001182 switch (comp_field->algo.dcomp) {
Philipp22611be2016-08-10 12:08:03 +02001183 case V42BIS:
1184 comp_field->v42bis_params = talloc_zero(comp_field, struct
1185 gprs_sndcp_dcomp_v42bis_params);
1186 rc = decode_dcomp_v42bis_params(comp_field->v42bis_params, src,
1187 src_len);
1188 if (rc < 0)
1189 talloc_free(comp_field->v42bis_params);
1190 break;
1191 case V44:
1192 comp_field->v44_params = talloc_zero(comp_field, struct
1193 gprs_sndcp_dcomp_v44_params);
1194 rc = decode_dcomp_v44_params(comp_field->v44_params, src,
1195 src_len);
1196 if (rc < 0)
1197 talloc_free(comp_field->v44_params);
1198 break;
1199
1200 /* If no suitable decoder is detected,
1201 * leave the remaining bytes undecoded */
1202 default:
1203 rc = src_len;
1204 }
1205
1206 if (rc < 0) {
1207 comp_field->v42bis_params = NULL;
1208 comp_field->v44_params = NULL;
1209 }
1210
1211 return rc;
1212}
1213
1214/* Decode data or protocol control information compression field
1215 * (see also: 3GPP TS 44.065, 6.6.1.1, Figure 9 and
1216 * 3GPP TS 44.065, 6.5.1.1, Figure 7) */
1217static int decode_comp_field(struct gprs_sndcp_comp_field *comp_field,
1218 const uint8_t *src, unsigned int src_len,
1219 const struct entity_algo_table *lt,
Stefan Sperlingc5721542018-11-07 16:33:39 +01001220 unsigned int lt_len,
1221 enum gprs_sndcp_xid_param_types compclass)
Philipp22611be2016-08-10 12:08:03 +02001222{
1223 int src_counter = 0;
1224 unsigned int len;
1225 int rc;
1226
1227 OSMO_ASSERT(comp_field);
1228
1229 /* Exit immediately if it is clear that no
1230 parseable data is present */
1231 if (src_len < 1 || !src)
1232 return -EINVAL;
1233
1234 /* Zero out target struct */
1235 memset(comp_field, 0, sizeof(struct gprs_sndcp_comp_field));
1236
1237 /* Decode Propose bit and Entity number */
1238 if ((*src) & 0x80)
1239 comp_field->p = 1;
1240 comp_field->entity = (*src) & 0x1F;
1241 src_counter++;
1242 src++;
1243
1244 /* Decode algorithm number (if present) */
1245 if (comp_field->p) {
Stefan Sperlingc5721542018-11-07 16:33:39 +01001246 switch (compclass) {
1247 case SNDCP_XID_PROTOCOL_COMPRESSION:
1248 comp_field->algo.pcomp = (*src) & 0x1F;
1249 break;
1250 case SNDCP_XID_DATA_COMPRESSION:
1251 comp_field->algo.dcomp = (*src) & 0x1F;
1252 break;
1253 default:
1254 return -EINVAL;
1255 }
Philipp22611be2016-08-10 12:08:03 +02001256 src_counter++;
1257 src++;
1258 }
1259 /* Alternatively take the information from the lookup table */
Stefan Sperlingc5721542018-11-07 16:33:39 +01001260 else {
1261 switch (compclass) {
1262 case SNDCP_XID_PROTOCOL_COMPRESSION:
1263 comp_field->algo.pcomp =
1264 lookup_algorithm_identifier_pcomp(comp_field->entity, lt, lt_len);
1265 break;
1266 case SNDCP_XID_DATA_COMPRESSION:
1267 comp_field->algo.dcomp =
1268 lookup_algorithm_identifier_dcomp(comp_field->entity, lt, lt_len);
1269 break;
1270 default:
1271 return -EINVAL;
1272 }
1273 }
Philipp22611be2016-08-10 12:08:03 +02001274
1275 /* Decode length field */
1276 len = *src;
1277 src_counter++;
1278 src++;
1279
1280 /* Decode PCOMP/DCOMP values */
1281 rc = decode_comp_values(comp_field, src, compclass);
1282 if (rc < 0)
1283 return -EINVAL;
1284 src_counter += rc;
1285 src += rc;
1286 len -= rc;
1287
1288 /* Decode algorithm specific payload data */
1289 if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION)
1290 rc = decode_pcomp_params(comp_field, src, len);
1291 else if (compclass == SNDCP_XID_DATA_COMPRESSION)
1292 rc = decode_dcomp_params(comp_field, src, len);
1293 else
1294 return -EINVAL;
1295
1296 if (rc >= 0)
1297 src_counter += rc;
1298 else
1299 return -EINVAL;
1300
1301 /* Return consumed length */
1302 return src_counter;
1303}
1304
1305/* Helper function for gprs_sndcp_decode_xid() to decode XID blocks */
1306static int decode_xid_block(struct llist_head *comp_fields, uint8_t tag,
1307 uint16_t tag_len, const uint8_t *val,
1308 const struct entity_algo_table *lt,
1309 unsigned int lt_len)
1310{
1311 struct gprs_sndcp_comp_field *comp_field;
1312 int byte_counter = 0;
1313 int comp_field_count = 0;
1314 int rc;
1315
1316 byte_counter = 0;
1317 do {
1318 /* Bail if more than the maximum number of
1319 comp_fields is generated */
1320 if (comp_field_count > MAX_ENTITIES * 2) {
1321 return -EINVAL;
1322 }
1323
1324 /* Parse and add comp_field */
1325 comp_field =
1326 talloc_zero(comp_fields, struct gprs_sndcp_comp_field);
1327
1328 rc = decode_comp_field(comp_field, val + byte_counter,
1329 tag_len - byte_counter, lt, lt_len, tag);
1330
1331 if (rc < 0) {
1332 talloc_free(comp_field);
1333 return -EINVAL;
1334 }
1335
1336 byte_counter += rc;
1337 llist_add(&comp_field->list, comp_fields);
1338 comp_field_count++;
1339 }
1340 while (tag_len - byte_counter > 0);
1341
1342 return byte_counter;
1343}
1344
1345/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */
Philippdb142dc2016-12-22 14:15:20 +01001346static int gprs_sndcp_decode_xid(int *version, struct llist_head *comp_fields,
Philipp22611be2016-08-10 12:08:03 +02001347 const uint8_t *src, unsigned int src_len,
Philippdb142dc2016-12-22 14:15:20 +01001348 const struct entity_algo_table *lt,
1349 unsigned int lt_len)
Philipp22611be2016-08-10 12:08:03 +02001350{
1351 int src_pos = 0;
1352 uint8_t tag;
1353 uint16_t tag_len;
1354 const uint8_t *val;
1355 int byte_counter = 0;
1356 int rc;
1357 int tlv_count = 0;
1358
Philippdb142dc2016-12-22 14:15:20 +01001359 /* Preset version value as invalid */
1360 if (version)
1361 *version = -1;
1362
Philipp22611be2016-08-10 12:08:03 +02001363 /* Valid TLV-Tag and types */
1364 static const struct tlv_definition sndcp_xid_def = {
1365 .def = {
1366 [SNDCP_XID_VERSION_NUMBER] = {TLV_TYPE_TLV,},
1367 [SNDCP_XID_DATA_COMPRESSION] = {TLV_TYPE_TLV,},
1368 [SNDCP_XID_PROTOCOL_COMPRESSION] = {TLV_TYPE_TLV,},
1369 },
1370 };
1371
1372 /* Parse TLV-Encoded SNDCP-XID message and defer payload
1373 to the apporpiate sub-parser functions */
1374 while (1) {
1375
1376 /* Bail if an the maximum number of TLV fields
1377 * have been parsed */
1378 if (tlv_count >= 3) {
1379 talloc_free(comp_fields);
1380 return -EINVAL;
1381 }
1382
1383 /* Parse TLV field */
1384 rc = tlv_parse_one(&tag, &tag_len, &val, &sndcp_xid_def,
1385 src + src_pos, src_len - src_pos);
1386 if (rc > 0)
1387 src_pos += rc;
1388 else {
1389 talloc_free(comp_fields);
1390 return -EINVAL;
1391 }
1392
Philippdb142dc2016-12-22 14:15:20 +01001393 /* Decode sndcp xid version number */
1394 if (version && tag == SNDCP_XID_VERSION_NUMBER)
1395 *version = val[0];
1396
Philipp22611be2016-08-10 12:08:03 +02001397 /* Decode compression parameters */
1398 if ((tag == SNDCP_XID_PROTOCOL_COMPRESSION)
1399 || (tag == SNDCP_XID_DATA_COMPRESSION)) {
1400 rc = decode_xid_block(comp_fields, tag, tag_len, val,
1401 lt, lt_len);
1402
1403 if (rc < 0) {
1404 talloc_free(comp_fields);
1405 return -EINVAL;
1406 } else
1407 byte_counter += rc;
1408 }
1409
1410 /* Stop when no further TLV elements can be expected */
1411 if (src_len - src_pos <= 2)
1412 break;
1413
1414 tlv_count++;
1415 }
1416
1417 return 0;
1418}
1419
1420/* Fill up lookutable from a list with comression entitiy fields */
1421static int gprs_sndcp_fill_table(struct
1422 entity_algo_table *lt,
1423 unsigned int lt_len,
1424 const struct llist_head *comp_fields)
1425{
1426 struct gprs_sndcp_comp_field *comp_field;
1427 int i = 0;
Stefan Sperlingc5721542018-11-07 16:33:39 +01001428 enum gprs_sndcp_xid_param_types compclass;
Philipp22611be2016-08-10 12:08:03 +02001429
1430 if (!comp_fields)
1431 return -EINVAL;
1432 if (!lt)
1433 return -EINVAL;
1434
Philippae9beda2016-09-28 15:10:14 +02001435 memset(lt, 0, sizeof(*lt));
Philipp22611be2016-08-10 12:08:03 +02001436
1437 llist_for_each_entry(comp_field, comp_fields, list) {
Stefan Sperlingc5721542018-11-07 16:33:39 +01001438 compclass = gprs_sndcp_get_compression_class(comp_field);
1439 switch (compclass) {
1440 case SNDCP_XID_PROTOCOL_COMPRESSION:
1441 lt[i].algo.pcomp = comp_field->algo.pcomp;
1442 break;
1443 case SNDCP_XID_DATA_COMPRESSION:
1444 lt[i].algo.dcomp = comp_field->algo.dcomp;
1445 break;
1446 case SNDCP_XID_INVALID_COMPRESSION:
1447 continue;
1448 default:
1449 memset(lt, 0, sizeof(*lt));
1450 return -EINVAL;
Philipp22611be2016-08-10 12:08:03 +02001451 }
Stefan Sperlingc5721542018-11-07 16:33:39 +01001452 lt[i].compclass = compclass;
1453 lt[i].entity = comp_field->entity;
1454 i++;
Philipp22611be2016-08-10 12:08:03 +02001455 }
1456
1457 return i;
1458}
1459
1460/* Complete comp field params
1461 * (if a param (dst) is not valid, it will be copied from source (src) */
1462static int complete_comp_field_params(struct gprs_sndcp_comp_field
1463 *comp_field_dst, const struct
1464 gprs_sndcp_comp_field *comp_field_src)
1465{
Stefan Sperlingc5721542018-11-07 16:33:39 +01001466 enum gprs_sndcp_xid_param_types compclass;
1467
1468 compclass = gprs_sndcp_get_compression_class(comp_field_dst);
1469 if (compclass == SNDCP_XID_INVALID_COMPRESSION)
Philipp22611be2016-08-10 12:08:03 +02001470 return -EINVAL;
1471
1472 if (comp_field_dst->rfc1144_params && comp_field_src->rfc1144_params) {
1473 if (comp_field_dst->rfc1144_params->s01 < 0) {
1474 comp_field_dst->rfc1144_params->s01 =
1475 comp_field_src->rfc1144_params->s01;
1476 }
1477 return 0;
1478 }
1479
1480 if (comp_field_dst->rfc2507_params && comp_field_src->rfc2507_params) {
1481
1482 if (comp_field_dst->rfc2507_params->f_max_period < 0) {
1483 comp_field_dst->rfc2507_params->f_max_period =
1484 comp_field_src->rfc2507_params->f_max_period;
1485 }
1486 if (comp_field_dst->rfc2507_params->f_max_time < 0) {
1487 comp_field_dst->rfc2507_params->f_max_time =
1488 comp_field_src->rfc2507_params->f_max_time;
1489 }
1490 if (comp_field_dst->rfc2507_params->max_header < 0) {
1491 comp_field_dst->rfc2507_params->max_header =
1492 comp_field_src->rfc2507_params->max_header;
1493 }
1494 if (comp_field_dst->rfc2507_params->tcp_space < 0) {
1495 comp_field_dst->rfc2507_params->tcp_space =
1496 comp_field_src->rfc2507_params->tcp_space;
1497 }
1498 if (comp_field_dst->rfc2507_params->non_tcp_space < 0) {
1499 comp_field_dst->rfc2507_params->non_tcp_space =
1500 comp_field_src->rfc2507_params->non_tcp_space;
1501 }
1502 return 0;
1503 }
1504
1505 if (comp_field_dst->rohc_params && comp_field_src->rohc_params) {
1506 if (comp_field_dst->rohc_params->max_cid < 0) {
1507 comp_field_dst->rohc_params->max_cid =
1508 comp_field_src->rohc_params->max_cid;
1509 }
1510 if (comp_field_dst->rohc_params->max_header < 0) {
1511 comp_field_dst->rohc_params->max_header =
1512 comp_field_src->rohc_params->max_header;
1513 }
1514 if (comp_field_dst->rohc_params->profile_len > 0) {
1515 memcpy(comp_field_dst->rohc_params->profile,
1516 comp_field_src->rohc_params->profile,
1517 sizeof(comp_field_dst->rohc_params->profile));
1518 comp_field_dst->rohc_params->profile_len =
1519 comp_field_src->rohc_params->profile_len;
1520 }
1521
1522 return 0;
1523 }
1524
1525 if (comp_field_dst->v42bis_params && comp_field_src->v42bis_params) {
1526 if (comp_field_dst->v42bis_params->p0 < 0) {
1527 comp_field_dst->v42bis_params->p0 =
1528 comp_field_src->v42bis_params->p0;
1529 }
1530 if (comp_field_dst->v42bis_params->p1 < 0) {
1531 comp_field_dst->v42bis_params->p1 =
1532 comp_field_src->v42bis_params->p1;
1533 }
1534 if (comp_field_dst->v42bis_params->p2 < 0) {
1535 comp_field_dst->v42bis_params->p2 =
1536 comp_field_src->v42bis_params->p2;
1537 }
1538 return 0;
1539 }
1540
1541 if (comp_field_dst->v44_params && comp_field_src->v44_params) {
1542 if (comp_field_dst->v44_params->c0 < 0) {
1543 comp_field_dst->v44_params->c0 =
1544 comp_field_src->v44_params->c0;
1545 }
1546 if (comp_field_dst->v44_params->p0 < 0) {
1547 comp_field_dst->v44_params->p0 =
1548 comp_field_src->v44_params->p0;
1549 }
1550 if (comp_field_dst->v44_params->p1t < 0) {
1551 comp_field_dst->v44_params->p1t =
1552 comp_field_src->v44_params->p1t;
1553 }
1554 if (comp_field_dst->v44_params->p1r < 0) {
1555 comp_field_dst->v44_params->p1r =
1556 comp_field_src->v44_params->p1r;
1557 }
1558 if (comp_field_dst->v44_params->p3t < 0) {
1559 comp_field_dst->v44_params->p3t =
1560 comp_field_src->v44_params->p3t;
1561 }
1562 if (comp_field_dst->v44_params->p3r < 0) {
1563 comp_field_dst->v44_params->p3r =
1564 comp_field_src->v44_params->p3r;
1565 }
1566 return 0;
1567 }
1568
1569 /* There should be at least exist one param set
1570 * in the destination struct, otherwise something
1571 * must be wrong! */
1572 return -EINVAL;
1573}
1574
1575/* Complete missing parameters in a comp_field */
1576static int gprs_sndcp_complete_comp_field(struct gprs_sndcp_comp_field
1577 *comp_field, const struct llist_head
1578 *comp_fields)
1579{
1580 struct gprs_sndcp_comp_field *comp_field_src;
1581 int rc = 0;
1582
1583 llist_for_each_entry(comp_field_src, comp_fields, list) {
1584 if (comp_field_src->entity == comp_field->entity) {
1585
1586 /* Complete header fields */
1587 if (comp_field_src->comp_len > 0) {
1588 memcpy(comp_field->comp,
1589 comp_field_src->comp,
1590 sizeof(comp_field_src->comp));
1591 comp_field->comp_len = comp_field_src->comp_len;
1592 }
1593
1594 /* Complete parameter fields */
1595 rc = complete_comp_field_params(comp_field,
1596 comp_field_src);
1597 }
1598 }
1599
1600 return rc;
1601}
1602
1603/* Complete missing parameters of all comp_field in a list */
1604static int gprs_sndcp_complete_comp_fields(struct llist_head
1605 *comp_fields_incomplete,
1606 const struct llist_head *comp_fields)
1607{
1608 struct gprs_sndcp_comp_field *comp_field_incomplete;
1609 int rc;
1610
1611 llist_for_each_entry(comp_field_incomplete, comp_fields_incomplete,
1612 list) {
1613
1614 rc = gprs_sndcp_complete_comp_field(comp_field_incomplete,
1615 comp_fields);
1616 if (rc < 0)
1617 return -EINVAL;
1618
1619 }
1620
1621 return 0;
1622}
1623
1624/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */
Philippdb142dc2016-12-22 14:15:20 +01001625struct llist_head *gprs_sndcp_parse_xid(int *version,
1626 const void *ctx,
Philipp22611be2016-08-10 12:08:03 +02001627 const uint8_t *src,
1628 unsigned int src_len,
1629 const struct llist_head
1630 *comp_fields_req)
1631{
1632 int rc;
1633 int lt_len;
1634 struct llist_head *comp_fields;
1635 struct entity_algo_table lt[MAX_ENTITIES * 2];
1636
Philippdb142dc2016-12-22 14:15:20 +01001637 /* In case of a zero length field, just exit */
1638 if (src_len == 0)
1639 return NULL;
1640
1641 /* We should go any further if we have a field length greater
1642 * zero and a null pointer as buffer! */
Philipp22611be2016-08-10 12:08:03 +02001643 OSMO_ASSERT(src);
1644
1645 comp_fields = talloc_zero(ctx, struct llist_head);
1646 INIT_LLIST_HEAD(comp_fields);
1647
1648 if (comp_fields_req) {
1649 /* Generate lookup table */
1650 lt_len =
1651 gprs_sndcp_fill_table(lt, MAX_ENTITIES * 2,
1652 comp_fields_req);
1653 if (lt_len < 0) {
1654 talloc_free(comp_fields);
1655 return NULL;
1656 }
1657
1658 /* Parse SNDCP-CID XID-Field */
Philippdb142dc2016-12-22 14:15:20 +01001659 rc = gprs_sndcp_decode_xid(version, comp_fields, src, src_len,
1660 lt, lt_len);
Philipp22611be2016-08-10 12:08:03 +02001661 if (rc < 0) {
1662 talloc_free(comp_fields);
1663 return NULL;
1664 }
1665
1666 rc = gprs_sndcp_complete_comp_fields(comp_fields,
1667 comp_fields_req);
1668 if (rc < 0) {
1669 talloc_free(comp_fields);
1670 return NULL;
1671 }
1672
1673 } else {
1674 /* Parse SNDCP-CID XID-Field */
Philippdb142dc2016-12-22 14:15:20 +01001675 rc = gprs_sndcp_decode_xid(version, comp_fields, src, src_len,
1676 NULL, 0);
Philipp22611be2016-08-10 12:08:03 +02001677 if (rc < 0) {
1678 talloc_free(comp_fields);
1679 return NULL;
1680 }
1681 }
1682
1683 return comp_fields;
1684}
1685
1686/* Helper for gprs_sndcp_dump_comp_fields(),
1687 * dumps protocol compression parameters */
1688static void dump_pcomp_params(const struct gprs_sndcp_comp_field
1689 *comp_field, unsigned int logl)
1690{
1691 int i;
1692
Stefan Sperlingc5721542018-11-07 16:33:39 +01001693 switch (comp_field->algo.pcomp) {
Philipp22611be2016-08-10 12:08:03 +02001694 case RFC_1144:
1695 if (comp_field->rfc1144_params == NULL) {
1696 LOGP(DSNDCP, logl,
1697 " gprs_sndcp_pcomp_rfc1144_params=NULL\n");
1698 break;
1699 }
1700 LOGP(DSNDCP, logl, " gprs_sndcp_pcomp_rfc1144_params {\n");
1701 LOGP(DSNDCP, logl,
1702 " nsapi_len=%d;\n",
1703 comp_field->rfc1144_params->nsapi_len);
1704 if (comp_field->rfc1144_params->nsapi_len == 0)
1705 LOGP(DSNDCP, logl, " nsapi[] = NULL;\n");
1706 for (i = 0; i < comp_field->rfc1144_params->nsapi_len; i++) {
1707 LOGP(DSNDCP, logl,
1708 " nsapi[%d]=%d;\n", i,
1709 comp_field->rfc1144_params->nsapi[i]);
1710 }
1711 LOGP(DSNDCP, logl, " s01=%d;\n",
1712 comp_field->rfc1144_params->s01);
1713 LOGP(DSNDCP, logl, " }\n");
1714 break;
1715 case RFC_2507:
1716 if (comp_field->rfc2507_params == NULL) {
1717 LOGP(DSNDCP, logl,
1718 " gprs_sndcp_pcomp_rfc2507_params=NULL\n");
1719 break;
1720 }
1721 LOGP(DSNDCP, logl, " gprs_sndcp_pcomp_rfc2507_params {\n");
1722 LOGP(DSNDCP, logl,
1723 " nsapi_len=%d;\n",
1724 comp_field->rfc2507_params->nsapi_len);
1725 if (comp_field->rfc2507_params->nsapi_len == 0)
1726 LOGP(DSNDCP, logl, " nsapi[] = NULL;\n");
1727 for (i = 0; i < comp_field->rfc2507_params->nsapi_len; i++) {
1728 LOGP(DSNDCP, logl,
1729 " nsapi[%d]=%d;\n", i,
1730 comp_field->rfc2507_params->nsapi[i]);
1731 }
1732 LOGP(DSNDCP, logl,
1733 " f_max_period=%d;\n",
1734 comp_field->rfc2507_params->f_max_period);
1735 LOGP(DSNDCP, logl,
1736 " f_max_time=%d;\n",
1737 comp_field->rfc2507_params->f_max_time);
1738 LOGP(DSNDCP, logl,
1739 " max_header=%d;\n",
1740 comp_field->rfc2507_params->max_header);
1741 LOGP(DSNDCP, logl,
1742 " tcp_space=%d;\n",
1743 comp_field->rfc2507_params->tcp_space);
1744 LOGP(DSNDCP, logl,
1745 " non_tcp_space=%d;\n",
1746 comp_field->rfc2507_params->non_tcp_space);
1747 LOGP(DSNDCP, logl, " }\n");
1748 break;
1749 case ROHC:
1750 if (comp_field->rohc_params == NULL) {
1751 LOGP(DSNDCP, logl,
1752 " gprs_sndcp_pcomp_rohc_params=NULL\n");
1753 break;
1754 }
1755 LOGP(DSNDCP, logl, " gprs_sndcp_pcomp_rohc_params {\n");
1756 LOGP(DSNDCP, logl,
1757 " nsapi_len=%d;\n",
1758 comp_field->rohc_params->nsapi_len);
1759 if (comp_field->rohc_params->nsapi_len == 0)
1760 LOGP(DSNDCP, logl, " nsapi[] = NULL;\n");
1761 for (i = 0; i < comp_field->rohc_params->nsapi_len; i++) {
1762 LOGP(DSNDCP, logl,
1763 " nsapi[%d]=%d;\n", i,
1764 comp_field->rohc_params->nsapi[i]);
1765 }
1766 LOGP(DSNDCP, logl,
1767 " max_cid=%d;\n", comp_field->rohc_params->max_cid);
1768 LOGP(DSNDCP, logl,
1769 " max_header=%d;\n",
1770 comp_field->rohc_params->max_header);
1771 LOGP(DSNDCP, logl,
1772 " profile_len=%d;\n",
1773 comp_field->rohc_params->profile_len);
1774 if (comp_field->rohc_params->profile_len == 0)
1775 LOGP(DSNDCP, logl, " profile[] = NULL;\n");
1776 for (i = 0; i < comp_field->rohc_params->profile_len; i++)
1777 LOGP(DSNDCP, logl,
1778 " profile[%d]=%04x;\n",
1779 i, comp_field->rohc_params->profile[i]);
1780 LOGP(DSNDCP, logl, " }\n");
1781 break;
1782 }
1783
1784}
1785
1786/* Helper for gprs_sndcp_dump_comp_fields(),
1787 * data protocol compression parameters */
1788static void dump_dcomp_params(const struct gprs_sndcp_comp_field
1789 *comp_field, unsigned int logl)
1790{
1791 int i;
1792
Stefan Sperlingc5721542018-11-07 16:33:39 +01001793 switch (comp_field->algo.dcomp) {
Philipp22611be2016-08-10 12:08:03 +02001794 case V42BIS:
1795 if (comp_field->v42bis_params == NULL) {
1796 LOGP(DSNDCP, logl,
1797 " gprs_sndcp_dcomp_v42bis_params=NULL\n");
1798 break;
1799 }
1800 LOGP(DSNDCP, logl, " gprs_sndcp_dcomp_v42bis_params {\n");
1801 LOGP(DSNDCP, logl,
1802 " nsapi_len=%d;\n",
1803 comp_field->v42bis_params->nsapi_len);
1804 if (comp_field->v42bis_params->nsapi_len == 0)
1805 LOGP(DSNDCP, logl, " nsapi[] = NULL;\n");
1806 for (i = 0; i < comp_field->v42bis_params->nsapi_len; i++)
1807 LOGP(DSNDCP, logl,
1808 " nsapi[%d]=%d;\n", i,
1809 comp_field->v42bis_params->nsapi[i]);
1810 LOGP(DSNDCP, logl, " p0=%d;\n",
1811 comp_field->v42bis_params->p0);
1812 LOGP(DSNDCP, logl, " p1=%d;\n",
1813 comp_field->v42bis_params->p1);
1814 LOGP(DSNDCP, logl, " p2=%d;\n",
1815 comp_field->v42bis_params->p2);
1816 LOGP(DSNDCP, logl, " }\n");
1817 break;
1818 case V44:
1819 if (comp_field->v44_params == NULL) {
1820 LOGP(DSNDCP, logl,
1821 " gprs_sndcp_dcomp_v44_params=NULL\n");
1822 break;
1823 }
1824 LOGP(DSNDCP, logl, " gprs_sndcp_dcomp_v44_params {\n");
1825 LOGP(DSNDCP, logl,
1826 " nsapi_len=%d;\n",
1827 comp_field->v44_params->nsapi_len);
1828 if (comp_field->v44_params->nsapi_len == 0)
1829 LOGP(DSNDCP, logl, " nsapi[] = NULL;\n");
1830 for (i = 0; i < comp_field->v44_params->nsapi_len; i++) {
1831 LOGP(DSNDCP, logl,
1832 " nsapi[%d]=%d;\n", i,
1833 comp_field->v44_params->nsapi[i]);
1834 }
1835 LOGP(DSNDCP, logl, " c0=%d;\n",
1836 comp_field->v44_params->c0);
1837 LOGP(DSNDCP, logl, " p0=%d;\n",
1838 comp_field->v44_params->p0);
1839 LOGP(DSNDCP, logl, " p1t=%d;\n",
1840 comp_field->v44_params->p1t);
1841 LOGP(DSNDCP, logl, " p1r=%d;\n",
1842 comp_field->v44_params->p1r);
1843 LOGP(DSNDCP, logl, " p3t=%d;\n",
1844 comp_field->v44_params->p3t);
1845 LOGP(DSNDCP, logl, " p3r=%d;\n",
1846 comp_field->v44_params->p3r);
1847 LOGP(DSNDCP, logl, " }\n");
1848 break;
1849 }
1850}
1851
1852/* Dump a list with SNDCP-XID fields (Debug) */
1853void gprs_sndcp_dump_comp_fields(const struct llist_head *comp_fields,
1854 unsigned int logl)
1855{
1856 struct gprs_sndcp_comp_field *comp_field;
1857 int i;
Stefan Sperlingc5721542018-11-07 16:33:39 +01001858 enum gprs_sndcp_xid_param_types compclass;
Philipp22611be2016-08-10 12:08:03 +02001859
1860 OSMO_ASSERT(comp_fields);
1861
1862 llist_for_each_entry(comp_field, comp_fields, list) {
Stefan Sperlingc5721542018-11-07 16:33:39 +01001863 compclass = gprs_sndcp_get_compression_class(comp_field);
Philipp22611be2016-08-10 12:08:03 +02001864 LOGP(DSNDCP, logl, "SNDCP-XID:\n");
1865 LOGP(DSNDCP, logl, "struct gprs_sndcp_comp_field {\n");
1866 LOGP(DSNDCP, logl, " entity=%d;\n", comp_field->entity);
Stefan Sperlingc5721542018-11-07 16:33:39 +01001867 switch (compclass) {
1868 case SNDCP_XID_PROTOCOL_COMPRESSION:
1869 LOGP(DSNDCP, logl, " algo=%d;\n", comp_field->algo.pcomp);
1870 break;
1871 case SNDCP_XID_DATA_COMPRESSION:
1872 LOGP(DSNDCP, logl, " algo=%d;\n", comp_field->algo.dcomp);
1873 break;
1874 default:
1875 LOGP(DSNDCP, logl, " algo invalid!\n");
1876 break;
1877 }
Philipp22611be2016-08-10 12:08:03 +02001878 LOGP(DSNDCP, logl, " comp_len=%d;\n", comp_field->comp_len);
1879 if (comp_field->comp_len == 0)
1880 LOGP(DSNDCP, logl, " comp[] = NULL;\n");
1881 for (i = 0; i < comp_field->comp_len; i++) {
1882 LOGP(DSNDCP, logl, " comp[%d]=%d;\n", i,
1883 comp_field->comp[i]);
1884 }
1885
Stefan Sperlingc5721542018-11-07 16:33:39 +01001886 switch (compclass) {
1887 case SNDCP_XID_PROTOCOL_COMPRESSION:
Philipp22611be2016-08-10 12:08:03 +02001888 dump_pcomp_params(comp_field, logl);
Stefan Sperlingc5721542018-11-07 16:33:39 +01001889 break;
1890 case SNDCP_XID_DATA_COMPRESSION:
Philipp22611be2016-08-10 12:08:03 +02001891 dump_dcomp_params(comp_field, logl);
Stefan Sperlingc5721542018-11-07 16:33:39 +01001892 break;
1893 default:
1894 LOGP(DSNDCP, logl, " compression algorithm invalid!\n");
1895 break;
Philipp22611be2016-08-10 12:08:03 +02001896 }
1897
1898 LOGP(DSNDCP, logl, "}\n");
1899 }
1900
1901}