This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.
dexter gerrit-no-reply at lists.osmocom.org
Review at https://gerrit.osmocom.org/641
Added SNDCP-XID encoder / decoder
The SNDCP-XID (or layer-3 xid) is used to exchange layer-3 parameters
such as compression. The encoder encodes a bytestream that is then
sent as regular XID field from LLC.
We will need the SNDCP-XID to negotiate the parameters for our
upcomming GPRS data and header compression features
Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e
---
M openbsc/include/openbsc/Makefile.am
A openbsc/include/openbsc/gprs_sndcp_xid.h
M openbsc/src/gprs/Makefile.am
A openbsc/src/gprs/gprs_sndcp_xid.c
4 files changed, 1,816 insertions(+), 3 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/41/641/1
diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am
index 9e8c554..b37103f 100644
--- a/openbsc/include/openbsc/Makefile.am
+++ b/openbsc/include/openbsc/Makefile.am
@@ -18,7 +18,7 @@
gprs_gb_parse.h smpp.h meas_feed.h \
gprs_gsup_client.h bsc_msg_filter.h \
oap.h oap_messages.h \
- gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h
+ gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h gprs_sndcp_xid.h
openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h
openbscdir = $(includedir)/openbsc
diff --git a/openbsc/include/openbsc/gprs_sndcp_xid.h b/openbsc/include/openbsc/gprs_sndcp_xid.h
new file mode 100644
index 0000000..53e24b8
--- /dev/null
+++ b/openbsc/include/openbsc/gprs_sndcp_xid.h
@@ -0,0 +1,213 @@
+#ifndef _GPRS_SNDCP_XID_H
+#define _GPRS_SNDCP_XID_H
+
+#include <stdint.h>
+#include <osmocom/core/linuxlist.h>
+
+#define CURRENT_SNDCP_VERSION 0 /* See TS 144 065, clause 8 */
+
+/* According to: TS 144 065 6.5.1.1 Format of the protocol control information
+ compression field (Figure 7)
+
+ TS 144 065 6.6.1.1 Format of the data compression
+ field (Figure 9) */
+
+struct gprs_sndcp_comp_field {
+ struct llist_head list;
+
+ /* Propose bit (P), see also: 6.5.1.1.2 and 6.6.1.1.2 */
+ unsigned int p;
+
+ /* Entity number, see also: 6.5.1.1.3 and 6.6.1.1.3 */
+ unsigned int entity;
+
+ /* gorithm identifier, see also: 6.5.1.1.4 and 6.6.1.1.4 */
+ unsigned int algo;
+
+ /* Number of contained PCOMP / DCOMP values */
+ unsigned int comp_len;
+
+ /* PCOMP / DCOMP values, see also: 6.5.1.1.5 and 6.6.1.1.5 */
+ unsigned int comp[16];
+
+ /* Note: Only one of the following struct pointers may,
+ be used unused pointers must be set to NULL! */
+ struct gprs_sndcp_hdrcomp_rfc1144_params *rfc1144_params;
+ struct gprs_sndcp_hdrcomp_rfc2507_params *rfc2507_params;
+ struct gprs_sndcp_hdrcomp_rohc_params *rohc_params;
+ struct gprs_sndcp_datacomp_v42bis_params *v42bis_params;
+ struct gprs_sndcp_datacomp_v44_params *v44_params;
+};
+
+/* According to: TS 144 065 6.5.1.1.4 Algorithm identifier */
+enum gprs_sndcp_hdr_comp_algo {
+ RFC_1144 = 0, /* TCP/IP header compression, see also 6.5.2 */
+ RFC_2507 = 1, /* TCP/UDP/IP header compression, see also: 6.5.3 */
+ ROHC = 2, /* Robust Header Compression, see also 6.5.4 */
+};
+
+/* According to: TS 144 065 6.5.1.1.4 Algorithm identifier */
+enum gprs_sndcp_data_comp_algo {
+ V42BIS = 0, /* V42bis data compression, see also 6.6.2 */
+ V44 = 1, /* V44 data compression, see also: 6.6.3 */
+};
+
+/* According to: TS 144 065 8 SNDCP XID parameters */
+enum gprs_sndcp_xid_param_types {
+ SNDCP_XID_VERSION_NUMBER = 0,
+ SNDCP_XID_DATA_COMPRESSION = 1, /* See also: subclause 6.6.1 */
+ SNDCP_XID_PROTOCOL_COMPRESSION = 2, /* See also: subclause 6.5.1 */
+};
+
+/* When the propose bit in an SNDCP-XID compression field is set to zero,
+ the algorithm identifier is stripped. The algoritm parameters are specific
+ for each algorithms. The following struct is used to pass the information
+ about the referenced algorithm to the parser. */
+struct gprs_sndcp_hdrcomp_entity_algo_table {
+ unsigned int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */
+ unsigned int algo; /* see also: 6.5.1.1.4 and 6.6.1.1.4 */
+ unsigned int compclass; /* Can be either SNDCP_XID_DATA_COMPRESSION or
+ SNDCP_XID_PROTOCOL_COMPRESSION */
+};
+
+
+
+/* According to: TS 144 065 6.5.2.1 Parameters (Table 5) */
+struct gprs_sndcp_hdrcomp_rfc1144_params {
+ unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */
+ unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */
+ unsigned int s01; /* (default 15) */
+};
+
+/* According to: TS 144 065 6.5.2.2 Assignment of PCOMP values */
+enum gprs_sndcp_hdrcomp_rfc1144_pcomp {
+ RFC1144_PCOMP1 = 0, /* Uncompressed TCP */
+ RFC1144_PCOMP2 = 1, /* Compressed TCP */
+ RFC1144_PCOMP_LEN = 2
+};
+
+
+
+/* According to: TS 144 065 6.5.3.1 Parameters (Table 6) */
+struct gprs_sndcp_hdrcomp_rfc2507_params {
+ unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */
+ unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */
+ unsigned int f_max_period; /* (default 256) */
+ unsigned int f_max_time; /* (default 5) */
+ unsigned int max_header; /* (default 168) */
+ unsigned int tcp_space; /* (default 15) */
+ unsigned int non_tcp_space; /* (default 15) */
+};
+
+/* According to: TS 144 065 6.5.3.2 Assignment of PCOMP values for RFC2507 */
+enum gprs_sndcp_hdrcomp_rfc2507_pcomp {
+ RFC2507_PCOMP1 = 0, /* Full Header */
+ RFC2507_PCOMP2 = 1, /* Compressed TCP */
+ RFC2507_PCOMP3 = 2, /* Compressed TCP non delta */
+ RFC2507_PCOMP4 = 3, /* Compressed non TCP */
+ RFC2507_PCOMP5 = 4, /* Context state */
+ RFC2507_PCOMP_LEN = 5
+};
+
+
+
+/* According to: TS 144 065 6.5.4.1 Parameter (Table 10) */
+struct gprs_sndcp_hdrcomp_rohc_params {
+ unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */
+ unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */
+ unsigned int max_cid; /* (default 15) */
+ unsigned int max_header; /* (default 168) */
+ unsigned int profile_len; /* (default 1) */
+ uint16_t profile[16]; /* (default 0, ROHC uncompressed) */
+};
+
+/* According to: TS 144 065 6.5.4.2 Assignment of PCOMP values for ROHC */
+enum gprs_sndcp_hdrcomp_rohc_pcomp {
+ ROHC_PCOMP1 = 0, /* ROHC small CIDs */
+ ROHC_PCOMP2 = 1, /* ROHC large CIDs */
+ ROHC_PCOMP_LEN = 2
+};
+
+/* ROHC compression profiles, see also:
+ http://www.iana.org/assignments/rohc-pro-ids/rohc-pro-ids.xhtml */
+enum gprs_sndcp_xid_rohc_profiles {
+ ROHC_UNCOMPRESSED = 0x0000, /* ROHC uncompressed [RFC5795] */
+ ROHC_RTP = 0x0001, /* ROHC RTP [RFC3095] */
+ ROHCV2_RTP = 0x0101, /* ROHCv2 RTP [RFC5225] */
+ ROHC_UDP = 0x0002, /* ROHC UDP [RFC3095] */
+ ROHCv2_UDP = 0x0102, /* ROHCv2 UDP [RFC5225] */
+ ROHC_ESP = 0x0003, /* ROHC ESP [RFC3095] */
+ ROHCV2_ESP = 0x0103, /* ROHCv2 ESP [RFC5225] */
+ ROHC_IP = 0x0004, /* ROHC IP [RFC3843] */
+ ROHCV2_IP = 0x0104, /* ROHCv2 IP [RFC5225] */
+ ROHC_LLA = 0x0005, /* ROHC LLA [RFC4362] */
+ ROHC_LLA_WITH_R_MODE = 0x0105, /* ROHC LLA with R-mode [RFC3408] */
+ ROHC_TCP = 0x0006, /* ROHC TCP [RFC6846] */
+ ROHC_RTP_UDP_LITE = 0x0007, /* ROHC RTP/UDP-Lite [RFC4019] */
+ ROHCV2_RTP_UDP_LITE = 0x0107, /* ROHCv2 RTP/UDP-Lite [RFC5225] */
+ ROHC_UDP_LITE = 0x0008, /* ROHC UDP-Lite [RFC4019] */
+ ROHCV2_UDP_LITE = 0x0108, /* ROHCv2 UDP-Lite [RFC5225] */
+};
+
+
+
+/* According to: TS 144 065 6.6.2.1 Parameters (Table 7a) */
+struct gprs_sndcp_datacomp_v42bis_params {
+ unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */
+ unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */
+ unsigned int p0; /* (default 3) */
+ unsigned int p1; /* (default 2048) */
+ unsigned int p2; /* (default 20) */
+
+};
+
+/* According to: ETSI TS 144 065 6.6.2.2 Assignment of DCOMP values */
+enum gprs_sndcp_datacomp_v42bis_dcomp {
+ V42BIS_DCOMP1 = 0, /* V42bis enabled */
+ V42BIS_DCOMP_LEN = 1
+};
+
+
+
+/* According to: TS 144 065 6.6.3.1 Parameters (Table 7c) */
+struct gprs_sndcp_datacomp_v44_params {
+ unsigned int nsapi_len; /* Number of applicable NSAPIs (default 0) */
+ unsigned int nsapi[11]; /* Applicable NSAPIs (default 0) */
+ unsigned int c0; /* (default 10000000) */
+ unsigned int p0; /* (default 3) */
+ unsigned int p1t; /* Refer to subclause 6.6.3.1.4 */
+ unsigned int p1r; /* Refer to subclause 6.6.3.1.5 */
+ unsigned int p3t; /* (default 3 x p1t) */
+ unsigned int p3r; /* (default 3 x p1r) */
+};
+
+/* According to: ETSI TS 144 065 6.6.3.2 Assignment of DCOMP values */
+enum gprs_sndcp_datacomp_v44_dcomp {
+ V44_DCOMP1 = 0, /* Packet method compressed */
+ V44_DCOMP2 = 1, /* Multi packet method compressed */
+ V44_DCOMP_LEN = 2
+};
+
+/* Transform a list with compression fields into an SNDCP-XID message (bytes) */
+int gprs_sndcp_compile_xid(struct llist_head *comp_fields, uint8_t * bytes,
+ unsigned int bytes_maxlen);
+
+/* Transform an SNDCP-XID message (bytes) into a list of SNDCP-XID fields */
+int gprs_sndcp_parse_xid(struct llist_head *comp_fields, uint8_t * bytes,
+ unsigned int bytes_len,
+ struct gprs_sndcp_hdrcomp_entity_algo_table *lt,
+ unsigned int lt_len);
+
+/* Free a list with SNDCP-XID fields */
+void gprs_sndcp_free_comp_fields(struct llist_head *comp_fields);
+
+/* Find out to which compression class the specified comp-field belongs
+ (header compression or data compression?) */
+int gprs_sndcp_get_compression_class(struct gprs_sndcp_comp_field
+ *comp_field);
+
+/* Dump a list with SNDCP-XID fields (Debug) */
+void gprs_sndcp_dump_comp_fields(struct llist_head *comp_fields);
+
+
+#endif
diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am
index b3a5137..67e9943 100644
--- a/openbsc/src/gprs/Makefile.am
+++ b/openbsc/src/gprs/Makefile.am
@@ -21,7 +21,7 @@
$(OSMO_LIBS) $(LIBCRYPTO_LIBS) -lrt
osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \
- slhc.c \
+ slhc.c gprs_sndcp_xid.c \
sgsn_main.c sgsn_vty.c sgsn_libgtp.c \
gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c \
gprs_llc_xid.c crc24.c \
@@ -32,7 +32,7 @@
osmo_sgsn_LDADD = \
$(top_builddir)/src/libcommon/libcommon.a \
-lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \
- $(LIBCRYPTO_LIBS) -lrt
+ $(LIBCRYPTO_LIBS) -lrt -lm
osmo_gtphub_SOURCES = gtphub_main.c gtphub.c gtphub_sock.c gtphub_ares.c \
gtphub_vty.c sgsn_ares.c gprs_utils.c
diff --git a/openbsc/src/gprs/gprs_sndcp_xid.c b/openbsc/src/gprs/gprs_sndcp_xid.c
new file mode 100644
index 0000000..dd8f535
--- /dev/null
+++ b/openbsc/src/gprs/gprs_sndcp_xid.c
@@ -0,0 +1,1600 @@
+/* GPRS SNDCP XID field encoding/decoding as per 3GPP TS 144 065 */
+
+/* (C) 2016 by Sysmocom s.f.m.c. GmbH
+ * All Rights Reserved
+ *
+ * Author: Philipp Maier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <math.h>
+#include <errno.h>
+
+#include <osmocom/core/utils.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/gsm/tlv.h>
+
+#include <openbsc/debug.h>
+#include <openbsc/gprs_llc.h>
+#include <openbsc/sgsn.h>
+#include <openbsc/gprs_sndcp_xid.h>
+
+
+/*
+ * FUNCTIONS RELATED TO SNDCP-XID ENCODING
+ */
+
+/* Encode applicable sapis (works the same in all three compression schemes) */
+static int encode_hdrcomp_applicable_sapis(uint8_t *bytes,
+ unsigned int *nsapis,
+ unsigned int nsapis_len)
+{
+ uint16_t blob;
+ unsigned int nsapi;
+ int i;
+
+ /* Encode applicable SAPIs */
+ blob = 0;
+ for (i = 0; i < nsapis_len; i++) {
+ nsapi = nsapis[i];
+ if ((nsapi < 5) || (nsapi > 15))
+ return -EINVAL;
+ blob |= (1 << nsapi);
+ }
+
+ /* Store result */
+ *bytes = (blob >> 8) & 0xFF;
+ bytes++;
+ *bytes = blob & 0xFF;
+
+ return 2;
+}
+
+/* Encode rfc1144 parameter field */
+static int encode_hdrcomp_rfc1144_params(uint8_t *bytes,
+ unsigned int bytes_maxlen,
+ struct
+ gprs_sndcp_hdrcomp_rfc1144_params
+ *params)
+{
+ /* NOTE: Buffer *bytes should offer at least 3 bytes
+ of space to store the generation results */
+
+ /* NOTE: Do not call manually, will be called by
+ encode_comp_field on purpose */
+
+ int bytes_counter = 0;
+ int rc;
+
+ /* Exit immediately if no source struct is available */
+ if (!params)
+ return -EINVAL;
+
+ /* Exit immediately if no sufficient memory space is supplied */
+ if ((bytes_maxlen < 3) || (!(bytes)))
+ return -EINVAL;
+
+ /* Exit if number of possible nsapis exceeds valid range
+ (Only 11 nsapis possible for PDP-Contexts) */
+ if ((params->nsapi_len < 0) || (params->nsapi_len > 11))
+ return -EINVAL;
+
+ /* Zero out buffer */
+ memset(bytes, 0, bytes_maxlen);
+
+ /* Encode applicable SAPIs */
+ rc = encode_hdrcomp_applicable_sapis(bytes, params->nsapi,
+ params->nsapi_len);
+ bytes += rc;
+ bytes_counter += rc;
+
+ /* Encode s01 */
+ *bytes = params->s01;
+ bytes++;
+ bytes_counter++;
+
+ /* Return generated length */
+ return bytes_counter;
+}
+
+
+/* Encode rfc2507 parameter field */
+static int encode_hdrcomp_rfc2507_params(uint8_t *bytes,
+ unsigned int bytes_maxlen,
+ struct
+ gprs_sndcp_hdrcomp_rfc2507_params
+ *params)
+{
+ /* NOTE: Buffer *bytes should offer at least 3 bytes
+ of space to store the generation results */
+
+ /* NOTE: Do not call manually, will be called
+ by encode_comp_field on purpose */
+
+ int bytes_counter = 0;
+ int rc;
+
+ /* Exit immediately if no source struct is available */
+ if (!params)
+ return -EINVAL;
+
+ /* Exit immediately if no sufficient memory space is supplied */
+ if ((bytes_maxlen < 9) || (!(bytes)))
+ return -EINVAL;
+
+ /* Exit if number of possible nsapis exceeds valid range
+ (Only 11 nsapis possible for PDP-Contexts) */
+ if ((params->nsapi_len < 0) || (params->nsapi_len > 11))
+ return -EINVAL;
+
+ /* Zero out buffer */
+ memset(bytes, 0, bytes_maxlen);
+
+ /* Encode applicable SAPIs */
+ rc = encode_hdrcomp_applicable_sapis(bytes, params->nsapi,
+ params->nsapi_len);
+ bytes += rc;
+ bytes_counter += rc;
+
+ /* Encode F_MAX_PERIOD */
+ if ((params->f_max_period < 1) || (params->f_max_period > 65535))
+ return -EINVAL;
+ *bytes = (params->f_max_period >> 8) & 0xFF;
+ bytes++;
+ bytes_counter++;
+ *bytes = (params->f_max_period) & 0xFF;
+ bytes++;
+ bytes_counter++;
+
+ /* Encode F_MAX_TIME */
+ if ((params->f_max_time < 1) || (params->f_max_time > 255))
+ return -EINVAL;
+ *bytes = params->f_max_time;
+ bytes++;
+ bytes_counter++;
+
+ /* Encode MAX_HEADER */
+ if ((params->max_header < 60) || (params->max_header > 255))
+ return -EINVAL;
+ *bytes = params->max_header;
+ bytes++;
+ bytes_counter++;
+
+ /* Encode TCP_SPACE */
+ if ((params->tcp_space < 3) || (params->tcp_space > 255))
+ return -EINVAL;
+ *bytes = params->tcp_space;
+ bytes++;
+ bytes_counter++;
+
+ /* Encode NON_TCP_SPACE */
+ if ((params->non_tcp_space < 3) || (params->tcp_space > 65535))
+ return -EINVAL;
+ *bytes = (params->non_tcp_space >> 8) & 0xFF;
+ bytes++;
+ bytes_counter++;
+ *bytes = (params->non_tcp_space) & 0xFF;
+ bytes++;
+ bytes_counter++;
+
+ /* Return generated length */
+ return bytes_counter;
+}
+
+
+/* Encode ROHC parameter field */
+static int encode_hdrcomp_rohc_params(uint8_t *bytes,
+ unsigned int bytes_maxlen,
+ struct gprs_sndcp_hdrcomp_rohc_params
+ *params)
+{
+ /* NOTE: Buffer *bytes should offer at least 36
+ (2 * 16 Profiles + 2 * 3 Parameter)
+ bytes of memory space to store generation results */
+
+ /* NOTE: Do not call manually, will be called
+ by encode_comp_field on purpose */
+
+ int i;
+ int bytes_counter = 0;
+ int rc;
+
+ /* Exit immediately if no source struct is available */
+ if (!params)
+ return -EINVAL;
+
+ /* Exit immediately if no sufficient memory space is supplied */
+ if ((bytes_maxlen < 38) || (!(bytes)))
+ return -EINVAL;
+
+ /* Exit if number of possible nsapis exceeds valid range
+ (Only 11 nsapis possible for PDP-Contexts) */
+ if ((params->nsapi_len < 0) || (params->nsapi_len > 11))
+ return -EINVAL;
+
+ /* Exit if number of ROHC profiles exceeds limit
+ (ROHC supports only a maximum of 16 different profiles) */
+ if ((params->profile_len < 0) || (params->profile_len > 16))
+ return -EINVAL;
+
+ /* Zero out buffer */
+ memset(bytes, 0, bytes_maxlen);
+
+ /* Encode applicable SAPIs */
+ rc = encode_hdrcomp_applicable_sapis(bytes, params->nsapi,
+ params->nsapi_len);
+ bytes += rc;
+ bytes_counter += rc;
+
+ /* Encode MAX_CID */
+ if (params->max_cid > 16383)
+ return -EINVAL;
+ *bytes = (params->max_cid >> 8) & 0xFF;
+ bytes++;
+ *bytes = params->max_cid & 0xFF;
+ bytes++;
+ bytes_counter += 2;
+
+ /* Encode MAX_HEADER */
+ if ((params->max_header < 60) || (params->max_header > 255))
+ return -EINVAL;
+ *bytes = (params->max_header >> 8) & 0xFF;
+ bytes++;
+ *bytes = params->max_header & 0xFF;
+ bytes++;
+ bytes_counter += 2;
+
+ /* Encode ROHC Profiles */
+ for (i = 0; i < params->profile_len; i++) {
+ *bytes = (params->profile[i] >> 8) & 0xFF;
+ bytes++;
+ *bytes = params->profile[i] & 0xFF;
+ bytes++;
+ bytes_counter += 2;
+ }
+
+ /* Return generated length */
+ return bytes_counter;
+}
+
+
+/* Encode V42bis parameter field */
+static int encode_datacomp_v42bis_params(uint8_t *bytes,
+ unsigned int bytes_maxlen,
+ struct
+ gprs_sndcp_datacomp_v42bis_params
+ *params)
+{
+ /* NOTE: Buffer *bytes should offer at least 6 bytes
+ of space to store the generation results */
+
+ /* NOTE: Do not call manually, will be called
+ by encode_comp_field on purpose */
+
+ int bytes_counter = 0;
+ int rc;
+
+ /* Exit immediately if no source struct is available */
+ if (!params)
+ return -EINVAL;
+
+ /* Exit immediately if no sufficient memory space is supplied */
+ if ((bytes_maxlen < 6) || (!(bytes)))
+ return -EINVAL;
+
+ /* Exit if number of possible nsapis exceeds valid range
+ (Only 11 nsapis possible for PDP-Contexts) */
+ if ((params->nsapi_len < 0) || (params->nsapi_len > 11))
+ return -EINVAL;
+
+ /* Zero out buffer */
+ memset(bytes, 0, bytes_maxlen);
+
+ /* Encode applicable SAPIs */
+ rc = encode_hdrcomp_applicable_sapis(bytes, params->nsapi,
+ params->nsapi_len);
+ bytes += rc;
+ bytes_counter += rc;
+
+ /* Encode P0 */
+ if (params->p0 > 3)
+ return -EINVAL;
+ *bytes = params->p0 & 0x03;
+ bytes++;
+ bytes_counter++;
+
+ /* Encode P1 */
+ if ((params->p1 < 512) || (params->p1 > 65535))
+ return -EINVAL;
+ *bytes = (params->p1 >> 8) & 0xFF;
+ bytes++;
+ *bytes = params->p1 & 0xFF;
+ bytes++;
+ bytes_counter += 2;
+
+ /* Encode P2 */
+ if ((params->p2 < 6) || (params->p2 > 250))
+ return -EINVAL;
+ *bytes = params->p2;
+ bytes++;
+ bytes_counter++;
+
+ /* Return generated length */
+ return bytes_counter;
+}
+
+
+/* Encode V44 parameter field */
+static int encode_datacomp_v44_params(uint8_t *bytes,
+ unsigned int bytes_maxlen,
+ struct gprs_sndcp_datacomp_v44_params
+ *params)
+{
+ /* NOTE: Buffer *bytes should offer at least 12
+ bytes of space to store the generation results */
+
+ /* NOTE: Do not call manually, will be called
+ by encode_comp_field on purpose */
+
+ int bytes_counter = 0;
+ int rc;
+
+ /* Exit immediately if no source struct is available */
+ if (!params)
+ return -EINVAL;
+
+ /* Exit immediately if no sufficient memory space is supplied */
+ if ((bytes_maxlen < 12) || (!(bytes)))
+ return -EINVAL;
+
+ /* Exit if number of possible nsapis exceeds valid range
+ (Only 11 nsapis possible for PDP-Contexts) */
+ if ((params->nsapi_len < 0) || (params->nsapi_len > 11))
+ return -EINVAL;
+
+ /* Zero out buffer */
+ memset(bytes, 0, bytes_maxlen);
+
+ /* Encode applicable SAPIs */
+ rc = encode_hdrcomp_applicable_sapis(bytes, params->nsapi,
+ params->nsapi_len);
+ bytes += rc;
+ bytes_counter += rc;
+
+ /* Encode C0 */
+ if ((params->c0 == 0x80) || (params->c0 == 0xC0)) {
+ *bytes = params->c0 & 0xC0;
+ bytes++;
+ bytes_counter++;
+ } else
+ return -EINVAL;
+
+ /* Encode P0 */
+ if (params->p0 > 3)
+ return -EINVAL;
+ *bytes = params->p0 & 0x03;
+ bytes++;
+ bytes_counter++;
+
+ /* Encode P1T */
+ if ((params->p1t < 256) || (params->p1t > 65535))
+ return -EINVAL;
+ *bytes = (params->p1t >> 8) & 0xFF;
+ bytes++;
+ *bytes = params->p1t & 0xFF;
+ bytes++;
+ bytes_counter += 2;
+
+ /* Encode P1R */
+ if ((params->p1r < 256) || (params->p1r > 65535))
+ return -EINVAL;
+ *bytes = (params->p1r >> 8) & 0xFF;
+ bytes++;
+ *bytes = params->p1r & 0xFF;
+ bytes++;
+ bytes_counter += 2;
+
+ /* Encode P3T */
+ if (params->p3t > 65535)
+ return -EINVAL;
+ if (params->p3t < 2 * params->p1t)
+ return -EINVAL;
+ *bytes = (params->p3t >> 8) & 0xFF;
+ bytes++;
+ *bytes = params->p3t & 0xFF;
+ bytes++;
+ bytes_counter += 2;
+
+ /* Encode P3R */
+ if (params->p3r > 65535)
+ return -EINVAL;
+ if (params->p3r < 2 * params->p1r)
+ return -EINVAL;
+ *bytes = (params->p3r >> 8) & 0xFF;
+ bytes++;
+ *bytes = params->p3r & 0xFF;
+ bytes++;
+ bytes_counter += 2;
+
+ /* Return generated length */
+ return bytes_counter;
+}
+
+
+/* Encode data or protocol control information compression field */
+static int encode_comp_field(uint8_t *bytes, unsigned int bytes_maxlen,
+ struct gprs_sndcp_comp_field *comp_field)
+{
+ int bytes_counter = 0;
+ int len;
+ int expected_length;
+ int i;
+
+ uint8_t payload_bytes[256];
+ int payload_bytes_len = -1;
+
+ /* If possible, try do encode payload bytes first */
+ if (comp_field->rfc1144_params)
+ payload_bytes_len =
+ encode_hdrcomp_rfc1144_params(payload_bytes,
+ sizeof(payload_bytes),
+ comp_field->
+ rfc1144_params);
+ else if (comp_field->rfc2507_params)
+ payload_bytes_len =
+ encode_hdrcomp_rfc2507_params(payload_bytes,
+ sizeof(payload_bytes),
+ comp_field->
+ rfc2507_params);
+ else if (comp_field->rohc_params)
+ payload_bytes_len =
+ encode_hdrcomp_rohc_params(payload_bytes,
+ sizeof(payload_bytes),
+ comp_field->rohc_params);
+ else if (comp_field->v42bis_params)
+ payload_bytes_len =
+ encode_datacomp_v42bis_params(payload_bytes,
+ sizeof(payload_bytes),
+ comp_field->
+ v42bis_params);
+ else if (comp_field->v44_params)
+ payload_bytes_len =
+ encode_datacomp_v44_params(payload_bytes,
+ sizeof(payload_bytes),
+ comp_field->v44_params);
+ else
+ return -EINVAL;
+
+ /* Exit immediately if payload byte generation failed */
+ if (payload_bytes_len < 0)
+ return -EINVAL;
+
+ /* Exit immediately if no source struct is available */
+ if (!comp_field)
+ return -EINVAL;
+
+ /* Check if comp_len is within bounds */
+ if ((comp_field->comp_len < 0) || (comp_field->comp_len > 16))
+ return -EINVAL;
+
+ /* Calculate length field of the data block */
+ if (comp_field->p) {
+ len =
+ payload_bytes_len +
+ ceil((double) (comp_field->comp_len) / 2.0);
+ expected_length = len + 3;
+ } else {
+ len = payload_bytes_len;
+ expected_length = len + 2;
+ }
+
+ /* Exit immediately if no sufficient memory space is supplied */
+ if ((bytes_maxlen < expected_length) || (!(bytes)))
+ return -EINVAL;
+
+ /* Check if the entity number is within bounds */
+ if ((comp_field->entity < 0) || (comp_field->entity > 0x1f))
+ return -EINVAL;
+
+ /* Check if the algorithm number is within bounds */
+ if ((comp_field->algo < 0) || (comp_field->algo > 0x1f))
+ return -EINVAL;
+
+ /* Zero out buffer */
+ memset(bytes, 0, bytes_maxlen);
+
+ /* Encode Propose bit */
+ if (comp_field->p)
+ *bytes |= (1 << 7);
+
+ /* Encode entity number */
+ *bytes |= comp_field->entity & 0x1F;
+ bytes++;
+ bytes_counter++;
+
+ /* Encode algorithm number */
+ if (comp_field->p) {
+ *bytes |= comp_field->algo & 0x1F;
+ bytes++;
+ bytes_counter++;
+ }
+
+ /* Encode length field */
+ *bytes |= len & 0xFF;
+ bytes++;
+ bytes_counter++;
+
+ /* Encode PCOMP/DCOMP values */
+ if (comp_field->p) {
+ for (i = 0; i < comp_field->comp_len; i++) {
+ /* Check if submitted PCOMP/DCOMP
+ values are within bounds */
+ if ((comp_field->comp[i] < 0)
+ || (comp_field->comp[i] > 0x0F))
+ return -EINVAL;
+
+ if (i & 1) {
+ *bytes |= comp_field->comp[i] & 0x0F;
+ bytes++;
+ bytes_counter++;
+ } else
+ *bytes |=
+ (comp_field->comp[i] << 4) & 0xF0;
+ }
+
+ if (i & 1) {
+ bytes++;
+ bytes_counter++;
+ }
+ }
+
+ /* Append payload bytes */
+ memcpy(bytes, payload_bytes, payload_bytes_len);
+ bytes_counter += payload_bytes_len;
+
+ /* Return generated length */
+ return bytes_counter;
+}
+
+
+/* Find out to which compression class the specified comp-field belongs
+ (header compression or data compression?) */
+int gprs_sndcp_get_compression_class(struct gprs_sndcp_comp_field
+ *comp_field)
+{
+ if (comp_field->rfc1144_params)
+ return SNDCP_XID_PROTOCOL_COMPRESSION;
+ else if (comp_field->rfc2507_params)
+ return SNDCP_XID_PROTOCOL_COMPRESSION;
+ else if (comp_field->rohc_params)
+ return SNDCP_XID_PROTOCOL_COMPRESSION;
+ else if (comp_field->v42bis_params)
+ return SNDCP_XID_DATA_COMPRESSION;
+ else if (comp_field->v44_params)
+ return SNDCP_XID_DATA_COMPRESSION;
+ else
+ return -EINVAL;
+}
+
+
+/* Convert all compression fields to bytstreams */
+static int gprs_sndcp_pack_fields(struct llist_head *comp_fields,
+ uint8_t * bytes,
+ unsigned int bytes_maxlen, int class)
+{
+ struct gprs_sndcp_comp_field *comp_field;
+ int byte_counter = 0;
+ int rc;
+
+ llist_for_each_entry(comp_field, comp_fields, list) {
+ if (class == gprs_sndcp_get_compression_class(comp_field)) {
+ rc = encode_comp_field(bytes + byte_counter,
+ bytes_maxlen - byte_counter,
+ comp_field);
+
+ /* Immediately stop on error */
+ if (rc < 0)
+ return rc;
+
+ byte_counter += rc;
+ }
+ }
+
+ /* Return generated length */
+ return byte_counter;
+}
+
+
+/* Transform a list with compression fields into an SNDCP-XID message (bytes) */
+int gprs_sndcp_compile_xid(struct llist_head *comp_fields, uint8_t *bytes,
+ unsigned int bytes_maxlen)
+{
+ int rc;
+ int byte_counter = 0;
+ uint8_t comp_bytes[512];
+ uint8_t xid_version_number[1] = { CURRENT_SNDCP_VERSION };
+
+ /* Exit immediately if no sufficient memory space is supplied */
+ if ((bytes_maxlen < 2 + sizeof(xid_version_number)) || (!(bytes)))
+ return -EINVAL;
+
+ /* Zero out buffer (just to be sure) */
+ memset(bytes, 0, bytes_maxlen);
+
+ /* Prepend header */
+ bytes =
+ tlv_put(bytes, SNDCP_XID_VERSION_NUMBER,
+ sizeof(xid_version_number), xid_version_number);
+ byte_counter += (sizeof(xid_version_number) + 2);
+
+ /* Add data compression fields */
+ rc = gprs_sndcp_pack_fields(comp_fields, comp_bytes,
+ sizeof(comp_bytes),
+ SNDCP_XID_DATA_COMPRESSION);
+ if (rc < 0)
+ return rc;
+ else if (rc > 0) {
+ bytes =
+ tlv_put(bytes, SNDCP_XID_DATA_COMPRESSION, rc,
+ comp_bytes);
+ byte_counter += rc + 2;
+ }
+
+ /* Add header compression fields */
+ rc = gprs_sndcp_pack_fields(comp_fields, comp_bytes,
+ sizeof(comp_bytes),
+ SNDCP_XID_PROTOCOL_COMPRESSION);
+ if (rc < 0)
+ return rc;
+ else if (rc > 0) {
+ bytes =
+ tlv_put(bytes, SNDCP_XID_PROTOCOL_COMPRESSION, rc,
+ comp_bytes);
+ byte_counter += rc + 2;
+ }
+
+ /* Return generated length */
+ return byte_counter;
+}
+
+
+
+
+
+
+
+
+
+
+/*
+ * FUNCTIONS RELATED TO SNDCP-XID DECODING
+ */
+
+/* Decode applicable sapis (works the same in all three compression schemes) */
+static int decode_hdrcomp_applicable_sapis(const uint8_t * bytes,
+ unsigned int bytes_len,
+ unsigned int *nsapis,
+ unsigned int *nsapis_len)
+{
+ uint16_t blob;
+ int i;
+ int nsapi_len = 0;
+
+ /* Exit immediately if no result can be stored */
+ if (!nsapis)
+ return -EINVAL;
+
+ /* Exit immediately if not enough input data is available */
+ if (bytes_len < 2)
+ return -EINVAL;
+
+ /* Read bitmask */
+ blob = *bytes;
+ blob = (blob << 8) & 0xFF00;
+ bytes++;
+ blob |= (*bytes) & 0xFF;
+ blob = (blob >> 5);
+
+ /* Decode applicable SAPIs */
+ for (i = 0; i < 15; i++) {
+ if ((blob >> i) & 1) {
+ nsapis[nsapi_len] = i + 5;
+ nsapi_len++;
+ }
+ }
+
+ /* Return consumed length */
+ *nsapis_len = nsapi_len;
+ return 2;
+}
+
+/* Decode 16 bit field */
+static int decode_hdrcomp_16_bit_field(const uint8_t * bytes,
+ unsigned int bytes_len,
+ int value_min, int value_max,
+ unsigned int *value_int,
+ uint16_t * value_uint16)
+{
+ uint16_t blob;
+
+ /* Reset values to zero (just to be sure) */
+ if (value_int)
+ *value_int = 0;
+ if (value_uint16)
+ *value_uint16 = 0;
+
+ /* Exit if not enough bytes are available */
+ if (bytes_len < 2)
+ return -EINVAL;
+
+ /* Decode bit value */
+ blob = *bytes;
+ blob = (blob << 8) & 0xFF00;
+ bytes++;
+ blob |= *bytes;
+
+ /* Check if parsed value is within bounds */
+ if (blob < value_min)
+ return -EINVAL;
+ if (blob > value_max)
+ return -EINVAL;
+
+ /* Hand back results to the caller */
+ if (value_int)
+ *value_int = blob;
+ if (value_uint16)
+ *value_uint16 = blob;
+
+ /* Return consumed length */
+ return 2;
+}
+
+/* Decode 8 bit field */
+static int decode_hdrcomp_8_bit_field(const uint8_t * bytes,
+ unsigned int bytes_len,
+ int value_min, int value_max,
+ unsigned int *value_int,
+ uint8_t * value_uint8)
+{
+ uint8_t blob;
+
+ /* Reset values to zero (just to be sure) */
+ if (value_int)
+ *value_int = 0;
+ if (value_uint8)
+ *value_uint8 = 0;
+
+ /* Exit if not enough bytes are available */
+ if (bytes_len < 1)
+ return -EINVAL;
+
+ /* Decode bit value */
+ blob = *bytes;
+
+ /* Check if parsed value is within bounds */
+ if (blob < value_min)
+ return -EINVAL;
+ if (blob > value_max)
+ return -EINVAL;
+
+ /* Hand back results to the caller */
+ if (value_int)
+ *value_int = blob;
+ if (value_uint8)
+ *value_uint8 = blob;
+
+ /* Return consumed length */
+ return 1;
+}
+
+
+
+
+/* Decode rfc1144 parameter field */
+static int decode_hdrcomp_rfc1144_params(const uint8_t * bytes,
+ unsigned int bytes_len,
+ struct
+ gprs_sndcp_hdrcomp_rfc1144_params
+ *params)
+{
+ int rc;
+ int byte_counter = 0;
+
+ /* Exit immediately if no result can be stored */
+ if (!params)
+ return -EINVAL;
+
+ /* Decode applicable SAPIs */
+ rc = decode_hdrcomp_applicable_sapis(bytes, bytes_len,
+ params->nsapi,
+ ¶ms->nsapi_len);
+ if (rc > 0) {
+ byte_counter += rc;
+ bytes += rc;
+ } else
+ return byte_counter;
+
+ /* Decode parameter S0 -1 */
+ rc = decode_hdrcomp_8_bit_field(bytes, bytes_len - byte_counter, 0,
+ 255, ¶ms->s01, NULL);
+ if (rc <= 0)
+ return byte_counter;
+ byte_counter += rc;
+ bytes += rc;
+
+ /* Return consumed length */
+ return byte_counter;
+}
+
+/* Decode rfc2507 parameter field */
+static int decode_hdrcomp_rfc2507_params(const uint8_t * bytes,
+ unsigned int bytes_len,
+ struct
+ gprs_sndcp_hdrcomp_rfc2507_params
+ *params)
+{
+ int rc;
+ int byte_counter = 0;
+
+ /* Exit immediately if no result can be stored */
+ if (!params)
+ return -EINVAL;
+
+ /* Decode applicable SAPIs */
+ rc = decode_hdrcomp_applicable_sapis(bytes, bytes_len,
+ params->nsapi,
+ ¶ms->nsapi_len);
+ if (rc > 0) {
+ byte_counter += rc;
+ bytes += rc;
+ } else
+ return byte_counter;
+
+ /* Decode F_MAX_PERIOD */
+ rc = decode_hdrcomp_16_bit_field(bytes, bytes_len - byte_counter,
+ 1, 65535, ¶ms->f_max_period,
+ NULL);
+ if (rc <= 0)
+ return byte_counter;
+ byte_counter += rc;
+ bytes += rc;
+
+ /* Decode F_MAX_TIME */
+ rc = decode_hdrcomp_8_bit_field(bytes, bytes_len - byte_counter, 1,
+ 255, ¶ms->f_max_time, NULL);
+ if (rc <= 0)
+ return byte_counter;
+ byte_counter += rc;
+ bytes += rc;
+
+ /* Decode MAX_HEADER */
+ rc = decode_hdrcomp_8_bit_field(bytes, bytes_len - byte_counter,
+ 60, 255, ¶ms->max_header,
+ NULL);
+ if (rc <= 0)
+ return byte_counter;
+ byte_counter += rc;
+ bytes += rc;
+
+ /* Decode TCP_SPACE */
+ rc = decode_hdrcomp_8_bit_field(bytes, bytes_len - byte_counter, 3,
+ 255, ¶ms->tcp_space, NULL);
+ if (rc <= 0)
+ return byte_counter;
+ byte_counter += rc;
+ bytes += rc;
+
+ /* Decode NON_TCP_SPACE */
+ rc = decode_hdrcomp_16_bit_field(bytes, bytes_len - byte_counter,
+ 3, 65535, ¶ms->non_tcp_space,
+ NULL);
+ if (rc <= 0)
+ return byte_counter;
+ byte_counter += rc;
+ bytes += rc;
+
+ /* Return consumed length */
+ return byte_counter;
+}
+
+/* Decode ROHC parameter field */
+static int decode_hdrcomp_rohc_params(const uint8_t * bytes,
+ unsigned int bytes_len,
+ struct gprs_sndcp_hdrcomp_rohc_params
+ *params)
+{
+ int rc;
+ int byte_counter = 0;
+ int i;
+
+ /* Exit immediately if no result can be stored */
+ if (!params)
+ return -EINVAL;
+
+ /* Decode applicable SAPIs */
+ rc = decode_hdrcomp_applicable_sapis(bytes, bytes_len,
+ params->nsapi,
+ ¶ms->nsapi_len);
+ if (rc <= 0)
+ return byte_counter;
+ byte_counter += rc;
+ bytes += rc;
+
+ /* Decode MAX_CID */
+ rc = decode_hdrcomp_16_bit_field(bytes, bytes_len - byte_counter,
+ 0, 16383, ¶ms->max_cid, NULL);
+ if (rc <= 0)
+ return byte_counter;
+ byte_counter += rc;
+ bytes += rc;
+
+ /* Decode MAX_HEADER */
+ rc = decode_hdrcomp_16_bit_field(bytes, bytes_len - byte_counter,
+ 60, 255, ¶ms->max_header,
+ NULL);
+ if (rc <= 0)
+ return byte_counter;
+ byte_counter += rc;
+ bytes += rc;
+
+ /* Decode Profiles */
+ for (i = 0; i < 16; i++) {
+ params->profile_len = 0;
+ rc = decode_hdrcomp_16_bit_field(bytes,
+ bytes_len - byte_counter,
+ 0, 65535, NULL,
+ ¶ms->profile[i]);
+ if (rc <= 0)
+ return byte_counter;
+ byte_counter += rc;
+ bytes += rc;
+ params->profile_len = i + 1;
+ }
+
+ /* Return consumed length */
+ return byte_counter;
+}
+
+
+/* Decode V42bis parameter field */
+static int decode_datacomp_v42bis_params(const uint8_t * bytes,
+ unsigned int bytes_len,
+ struct
+ gprs_sndcp_datacomp_v42bis_params
+ *params)
+{
+ int rc;
+ int byte_counter = 0;
+
+ /* Exit immediately if no result can be stored */
+ if (!params)
+ return -EINVAL;
+
+ /* Decode applicable SAPIs */
+ rc = decode_hdrcomp_applicable_sapis(bytes, bytes_len,
+ params->nsapi,
+ ¶ms->nsapi_len);
+ if (rc > 0) {
+ byte_counter += rc;
+ bytes += rc;
+ } else
+ return byte_counter;
+
+ /* Decode P0 */
+ rc = decode_hdrcomp_8_bit_field(bytes, bytes_len - byte_counter, 0,
+ 3, ¶ms->p0, NULL);
+ if (rc <= 0)
+ return byte_counter;
+ byte_counter += rc;
+ bytes += rc;
+
+ /* Decode P1 */
+ rc = decode_hdrcomp_16_bit_field(bytes, bytes_len - byte_counter,
+ 512, 65535, ¶ms->p1, NULL);
+ if (rc <= 0)
+ return byte_counter;
+ byte_counter += rc;
+ bytes += rc;
+
+ /* Decode P2 */
+ rc = decode_hdrcomp_8_bit_field(bytes, bytes_len - byte_counter, 6,
+ 250, ¶ms->p2, NULL);
+ if (rc <= 0)
+ return byte_counter;
+ byte_counter += rc;
+ bytes += rc;
+
+ /* Return consumed length */
+ return byte_counter;
+}
+
+
+/* Decode V44 parameter field */
+static int decode_datacomp_v44_params(const uint8_t * bytes,
+ unsigned int bytes_len,
+ struct gprs_sndcp_datacomp_v44_params
+ *params)
+{
+ int rc;
+ int byte_counter = 0;
+
+ /* Exit immediately if no result can be stored */
+ if (!params)
+ return -EINVAL;
+
+ /* Decode applicable SAPIs */
+ rc = decode_hdrcomp_applicable_sapis(bytes, bytes_len,
+ params->nsapi,
+ ¶ms->nsapi_len);
+ if (rc > 0) {
+ byte_counter += rc;
+ bytes += rc;
+ } else
+ return byte_counter;
+
+ /* Decode C0 */
+ rc = decode_hdrcomp_8_bit_field(bytes, bytes_len - byte_counter, 0,
+ 255, ¶ms->c0, NULL);
+ if (rc <= 0)
+ return byte_counter;
+ if ((params->c0 != 0x80) && (params->c0 != 0xC0))
+ return -EINVAL;
+ byte_counter += rc;
+ bytes += rc;
+
+ /* Decode P0 */
+ rc = decode_hdrcomp_8_bit_field(bytes, bytes_len - byte_counter, 0,
+ 3, ¶ms->p0, NULL);
+ if (rc <= 0)
+ return byte_counter;
+ byte_counter += rc;
+ bytes += rc;
+
+ /* Decode P1T */
+ rc = decode_hdrcomp_16_bit_field(bytes, bytes_len - byte_counter,
+ 265, 65535, ¶ms->p1t, NULL);
+ if (rc <= 0)
+ return byte_counter;
+ byte_counter += rc;
+ bytes += rc;
+
+ /* Decode P1R */
+ rc = decode_hdrcomp_16_bit_field(bytes, bytes_len - byte_counter,
+ 265, 65535, ¶ms->p1r, NULL);
+ if (rc <= 0)
+ return byte_counter;
+ byte_counter += rc;
+ bytes += rc;
+
+ /* Decode P3T */
+ rc = decode_hdrcomp_16_bit_field(bytes, bytes_len - byte_counter,
+ 265, 65535, ¶ms->p3t, NULL);
+ if (rc <= 0)
+ return byte_counter;
+ if (params->p3t < 2 * params->p1t)
+ return -EINVAL;
+ byte_counter += rc;
+ bytes += rc;
+
+ /* Decode P3R */
+ rc = decode_hdrcomp_16_bit_field(bytes, bytes_len - byte_counter,
+ 265, 65535, ¶ms->p3r, NULL);
+ if (rc <= 0)
+ return byte_counter;
+ if (params->p3r < 2 * params->p1r)
+ return -EINVAL;
+ byte_counter += rc;
+ bytes += rc;
+
+ /* Return consumed length */
+ return byte_counter;
+}
+
+
+/* Lookup algorithm identfier by entity ID */
+static int lookup_algorithm_identifier(int entity,
+ struct
+ gprs_sndcp_hdrcomp_entity_algo_table
+ *lt, unsigned int lt_len,
+ int compclass)
+{
+ int i;
+ if ((lt) && (lt_len > 0)) {
+ for (i = 0; i < lt_len; i++) {
+ if ((lt[i].entity == entity)
+ && (lt[i].compclass == compclass))
+ return lt[i].algo;
+ }
+ }
+
+ return -1;
+}
+
+/* Decode data or protocol control information compression field */
+static int decode_comp_field(const uint8_t * bytes, unsigned int bytes_len,
+ struct gprs_sndcp_comp_field *comp_field,
+ struct
+ gprs_sndcp_hdrcomp_entity_algo_table
+ *lt, unsigned int lt_len, int compclass)
+{
+ int byte_counter = 0;
+ unsigned int len;
+ int i;
+ int rc;
+
+ /* Exit immediately if it is clear that no
+ parseable data is present */
+ if ((bytes_len < 1) || (!(bytes)))
+ return -EINVAL;
+
+ /* Exit immediately if no result can be stored */
+ if (!comp_field)
+ return -EINVAL;
+
+ /* Zero out target struct */
+ memset(comp_field, 0, sizeof(struct gprs_sndcp_comp_field));
+
+ /* Decode Propose bit and Entity number */
+ if ((*bytes) & 0x80)
+ comp_field->p = 1;
+ comp_field->entity = (*bytes) & 0x1F;
+ byte_counter++;
+ bytes++;
+
+ /* Decode algorithm number (if present) */
+ if (comp_field->p) {
+ comp_field->algo = (*bytes) & 0x1F;
+ byte_counter++;
+ bytes++;
+ }
+ /* Alternatively take the information from the lookup table */
+ else
+ comp_field->algo =
+ lookup_algorithm_identifier(comp_field->entity, lt,
+ lt_len, compclass);
+
+ /* Decode length field */
+ len = *bytes;
+ byte_counter++;
+ bytes++;
+
+
+ /* Decode PCOMP/DCOMP values */
+ if (comp_field->p) {
+ /* Determine the number of expected PCOMP/DCOMP values */
+ if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) {
+ /* For protocol compression */
+ switch (comp_field->algo) {
+ case RFC_1144:
+ comp_field->comp_len = RFC1144_PCOMP_LEN;
+ break;
+ case RFC_2507:
+ comp_field->comp_len = RFC2507_PCOMP_LEN;
+ break;
+ case ROHC:
+ comp_field->comp_len = ROHC_PCOMP_LEN;
+ break;
+
+ /* Exit if the algorithem type encodes
+ something unknown / unspecified */
+ default:
+ return -EINVAL;
+ }
+ } else {
+ /* For data compression */
+ switch (comp_field->algo) {
+ case V42BIS:
+ comp_field->comp_len = V42BIS_DCOMP_LEN;
+ break;
+ case V44:
+ comp_field->comp_len = V44_DCOMP_LEN;
+ break;
+
+ /* Exit if the algorithem type encodes
+ something unknown / unspecified */
+ default:
+ return -EINVAL;
+ }
+ }
+
+ for (i = 0; i < comp_field->comp_len; i++) {
+ if (i & 1) {
+ comp_field->comp[i] = (*bytes) & 0x0F;
+ bytes++;
+ byte_counter++;
+ len--;
+ } else
+ comp_field->comp[i] =
+ ((*bytes) >> 4) & 0x0F;
+ }
+
+ if (i & 1) {
+ bytes++;
+ byte_counter++;
+ len--;
+ }
+ }
+
+ /* Decode algorithm specific payload data */
+ if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) {
+ /* For protocol compression */
+ switch (comp_field->algo) {
+ case RFC_1144:
+ comp_field->rfc1144_params =
+ talloc_zero(NULL,
+ struct
+ gprs_sndcp_hdrcomp_rfc1144_params);
+ rc = decode_hdrcomp_rfc1144_params(bytes, len,
+ comp_field->
+ rfc1144_params);
+ break;
+ case RFC_2507:
+ comp_field->rfc2507_params =
+ talloc_zero(NULL,
+ struct
+ gprs_sndcp_hdrcomp_rfc2507_params);
+ rc = decode_hdrcomp_rfc2507_params(bytes, len,
+ comp_field->
+ rfc2507_params);
+ break;
+ case ROHC:
+ comp_field->rohc_params =
+ talloc_zero(NULL,
+ struct
+ gprs_sndcp_hdrcomp_rohc_params);
+ rc = decode_hdrcomp_rohc_params(bytes, len,
+ comp_field->
+ rohc_params);
+ break;
+
+ /* If no suitable decoder is detected,
+ leave the remaining bytes undecoded */
+ default:
+ rc = len;
+ }
+ } else {
+ /* For data compression */
+ switch (comp_field->algo) {
+ case V42BIS:
+ comp_field->v42bis_params =
+ talloc_zero(NULL,
+ struct
+ gprs_sndcp_datacomp_v42bis_params);
+ rc = decode_datacomp_v42bis_params(bytes, len,
+ comp_field->
+ v42bis_params);
+ break;
+ case V44:
+ comp_field->v44_params =
+ talloc_zero(NULL,
+ struct
+ gprs_sndcp_datacomp_v44_params);
+ rc = decode_datacomp_v44_params(bytes, len,
+ comp_field->
+ v44_params);
+ break;
+
+ /* If no suitable decoder is detected,
+ leave the remaining bytes undecoded */
+ default:
+ rc = len;
+ }
+ }
+
+ if (rc >= 0)
+ byte_counter += rc;
+ else
+ return -EINVAL;
+
+
+ /* Return consumed length */
+ return byte_counter;
+}
+
+/* Transform an SNDCP-XID message (bytes) into a list of SNDCP-XID fields */
+int gprs_sndcp_parse_xid(struct llist_head *comp_fields, uint8_t * bytes,
+ unsigned int bytes_len,
+ struct gprs_sndcp_hdrcomp_entity_algo_table
+ *lt, unsigned int lt_len)
+{
+ int bytes_pos = 0;
+ uint8_t tag;
+ uint16_t tag_len;
+ const uint8_t *val;
+ struct gprs_sndcp_comp_field *comp_field;
+ int rc;
+ int byte_counter = 0;
+
+ /* Valid TLV-Tag and types */
+ static const struct tlv_definition sndcp_xid_def = {
+ .def = {
+ [SNDCP_XID_VERSION_NUMBER] = {TLV_TYPE_TLV,},
+ [SNDCP_XID_DATA_COMPRESSION] = {TLV_TYPE_TLV,},
+ [SNDCP_XID_PROTOCOL_COMPRESSION] = {TLV_TYPE_TLV,},
+ },
+ };
+
+ /* Parse TLV-Encoded SNDCP-XID message and defer payload
+ to the apporpiate sub-parser functions */
+ while (1) {
+ bytes_pos +=
+ tlv_parse_one(&tag, &tag_len, &val, &sndcp_xid_def,
+ bytes + bytes_pos,
+ bytes_len - bytes_pos);
+
+ /* Decode compression parameters */
+ if ((tag == SNDCP_XID_PROTOCOL_COMPRESSION)
+ || (tag == SNDCP_XID_DATA_COMPRESSION)) {
+ byte_counter = 0;
+ do {
+ comp_field =
+ talloc_zero(NULL,
+ struct
+ gprs_sndcp_comp_field);
+ rc = decode_comp_field(val + byte_counter,
+ tag_len -
+ byte_counter,
+ comp_field, lt,
+ lt_len, tag);
+
+ if (rc > 0) {
+ byte_counter += rc;
+ llist_add(&comp_field->list,
+ comp_fields);
+ } else {
+ talloc_free(comp_field);
+ return -EINVAL;
+ }
+ }
+ while (tag_len - byte_counter > 0);
+ }
+
+ /* Stop when no further TLV elements can be expected */
+ if (bytes_len - bytes_pos <= 2)
+ break;
+ }
+
+ return 0;
+}
+
+/* Free a list with SNDCP-XID fields */
+void gprs_sndcp_free_comp_fields(struct llist_head *comp_fields)
+{
+ struct gprs_sndcp_comp_field *comp_field;
+
+ /* Exit immediately if no list is present */
+ if (!(comp_fields))
+ return;
+
+ llist_for_each_entry(comp_field, comp_fields, list) {
+ if (comp_field->rfc1144_params)
+ talloc_free(comp_field->rfc1144_params);
+ if (comp_field->rfc2507_params)
+ talloc_free(comp_field->rfc2507_params);
+ if (comp_field->rohc_params)
+ talloc_free(comp_field->rohc_params);
+ if (comp_field->v42bis_params)
+ talloc_free(comp_field->v42bis_params);
+ if (comp_field->v44_params)
+ talloc_free(comp_field->v44_params);
+
+ talloc_free(comp_field);
+ }
+}
+
+/* Dump a list with SNDCP-XID fields (Debug) */
+void gprs_sndcp_dump_comp_fields(struct llist_head *comp_fields)
+{
+ struct gprs_sndcp_comp_field *comp_field;
+ int i;
+ int compclass;
+
+ llist_for_each_entry(comp_field, comp_fields, list) {
+ LOGP(DSNDCP, LOGL_DEBUG, "SNDCP-XID:\n");
+ LOGP(DSNDCP, LOGL_DEBUG,
+ "struct gprs_sndcp_comp_field {\n");
+ LOGP(DSNDCP, LOGL_DEBUG, " p=%i;\n", comp_field->p);
+ LOGP(DSNDCP, LOGL_DEBUG, " entity=%i;\n",
+ comp_field->entity);
+ LOGP(DSNDCP, LOGL_DEBUG, " algo=%i;\n",
+ comp_field->algo);
+ LOGP(DSNDCP, LOGL_DEBUG, " comp_len=%i;\n",
+ comp_field->comp_len);
+ if (comp_field->comp_len == 0)
+ LOGP(DSNDCP, LOGL_DEBUG, " comp[] = NULL;\n");
+ for (i = 0; i < comp_field->comp_len; i++)
+ LOGP(DSNDCP, LOGL_DEBUG, " comp[%i]=%i;\n", i,
+ comp_field->comp[i]);
+
+ compclass = gprs_sndcp_get_compression_class(comp_field);
+
+ if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) {
+ switch (comp_field->algo) {
+ case RFC_1144:
+ LOGP(DSNDCP, LOGL_DEBUG,
+ " gprs_sndcp_hdrcomp_rfc1144_params {\n");
+ LOGP(DSNDCP, LOGL_DEBUG,
+ " nsapi_len=%i;\n",
+ comp_field->rfc1144_params->
+ nsapi_len);
+ if (comp_field->rfc1144_params->
+ nsapi_len == 0)
+ LOGP(DSNDCP, LOGL_DEBUG,
+ " nsapi[] = NULL;\n");
+ for (i = 0;
+ i <
+ comp_field->rfc1144_params->nsapi_len;
+ i++)
+ LOGP(DSNDCP, LOGL_DEBUG,
+ " nsapi[%i]=%i;\n", i,
+ comp_field->rfc1144_params->
+ nsapi[i]);
+ LOGP(DSNDCP, LOGL_DEBUG, " s01=%i;\n",
+ comp_field->rfc1144_params->s01);
+ LOGP(DSNDCP, LOGL_DEBUG, " }\n");
+ break;
+ case RFC_2507:
+ LOGP(DSNDCP, LOGL_DEBUG,
+ " gprs_sndcp_hdrcomp_rfc2507_params {\n");
+ LOGP(DSNDCP, LOGL_DEBUG,
+ " nsapi_len=%i;\n",
+ comp_field->rfc2507_params->
+ nsapi_len);
+ if (comp_field->rfc2507_params->
+ nsapi_len == 0)
+ LOGP(DSNDCP, LOGL_DEBUG,
+ " nsapi[] = NULL;\n");
+ for (i = 0;
+ i <
+ comp_field->rfc2507_params->nsapi_len;
+ i++)
+ LOGP(DSNDCP, LOGL_DEBUG,
+ " nsapi[%i]=%i;\n", i,
+ comp_field->rfc2507_params->
+ nsapi[i]);
+ LOGP(DSNDCP, LOGL_DEBUG,
+ " f_max_period=%i;\n",
+ comp_field->rfc2507_params->
+ f_max_period);
+ LOGP(DSNDCP, LOGL_DEBUG,
+ " f_max_time=%i;\n",
+ comp_field->rfc2507_params->
+ f_max_time);
+ LOGP(DSNDCP, LOGL_DEBUG,
+ " max_header=%i;\n",
+ comp_field->rfc2507_params->
+ max_header);
+ LOGP(DSNDCP, LOGL_DEBUG,
+ " tcp_space=%i;\n",
+ comp_field->rfc2507_params->
+ tcp_space);
+ LOGP(DSNDCP, LOGL_DEBUG,
+ " non_tcp_space=%i;\n",
+ comp_field->rfc2507_params->
+ non_tcp_space);
+ LOGP(DSNDCP, LOGL_DEBUG, " }\n");
+ break;
+ case ROHC:
+ LOGP(DSNDCP, LOGL_DEBUG,
+ " gprs_sndcp_hdrcomp_rohc_params {\n");
+ LOGP(DSNDCP, LOGL_DEBUG,
+ " nsapi_len=%i;\n",
+ comp_field->rohc_params->nsapi_len);
+ if (comp_field->rohc_params->nsapi_len ==
+ 0)
+ LOGP(DSNDCP, LOGL_DEBUG,
+ " nsapi[] = NULL;\n");
+ for (i = 0;
+ i <
+ comp_field->rohc_params->nsapi_len;
+ i++)
+ LOGP(DSNDCP, LOGL_DEBUG,
+ " nsapi[%i]=%i;\n", i,
+ comp_field->rohc_params->
+ nsapi[i]);
+ LOGP(DSNDCP, LOGL_DEBUG,
+ " max_cid=%i;\n",
+ comp_field->rohc_params->max_cid);
+ LOGP(DSNDCP, LOGL_DEBUG,
+ " max_header=%i;\n",
+ comp_field->rohc_params->max_header);
+ if (comp_field->rohc_params->profile_len ==
+ 0)
+ LOGP(DSNDCP, LOGL_DEBUG,
+ " profile[] = NULL;\n");
+ for (i = 0;
+ i <
+ comp_field->rohc_params->profile_len;
+ i++)
+ LOGP(DSNDCP, LOGL_DEBUG,
+ " profile[%i]=%04x;\n",
+ i,
+ comp_field->rohc_params->
+ profile[i]);
+ LOGP(DSNDCP, LOGL_DEBUG, " }\n");
+ break;
+ }
+ } else if (compclass == SNDCP_XID_DATA_COMPRESSION) {
+ switch (comp_field->algo) {
+ case V42BIS:
+ LOGP(DSNDCP, LOGL_DEBUG,
+ " gprs_sndcp_datacomp_v42bis_params {\n");
+ LOGP(DSNDCP, LOGL_DEBUG,
+ " nsapi_len=%i;\n",
+ comp_field->v42bis_params->nsapi_len);
+ if (comp_field->v42bis_params->nsapi_len ==
+ 0)
+ LOGP(DSNDCP, LOGL_DEBUG,
+ " nsapi[] = NULL;\n");
+ for (i = 0;
+ i <
+ comp_field->v42bis_params->nsapi_len;
+ i++)
+ LOGP(DSNDCP, LOGL_DEBUG,
+ " nsapi[%i]=%i;\n", i,
+ comp_field->v42bis_params->
+ nsapi[i]);
+ LOGP(DSNDCP, LOGL_DEBUG, " p0=%i;\n",
+ comp_field->v42bis_params->p0);
+ LOGP(DSNDCP, LOGL_DEBUG, " p1=%i;\n",
+ comp_field->v42bis_params->p1);
+ LOGP(DSNDCP, LOGL_DEBUG, " p2=%i;\n",
+ comp_field->v42bis_params->p2);
+ LOGP(DSNDCP, LOGL_DEBUG, " }\n");
+ break;
+ case V44:
+ LOGP(DSNDCP, LOGL_DEBUG,
+ " gprs_sndcp_datacomp_v44_params {\n");
+ LOGP(DSNDCP, LOGL_DEBUG,
+ " nsapi_len=%i;\n",
+ comp_field->v44_params->nsapi_len);
+ if (comp_field->v44_params->nsapi_len == 0)
+ LOGP(DSNDCP, LOGL_DEBUG,
+ " nsapi[] = NULL;\n");
+ for (i = 0;
+ i < comp_field->v44_params->nsapi_len;
+ i++)
+ LOGP(DSNDCP, LOGL_DEBUG,
+ " nsapi[%i]=%i;\n", i,
+ comp_field->v44_params->
+ nsapi[i]);
+ LOGP(DSNDCP, LOGL_DEBUG, " c0=%i;\n",
+ comp_field->v44_params->c0);
+ LOGP(DSNDCP, LOGL_DEBUG, " p0=%i;\n",
+ comp_field->v44_params->p0);
+ LOGP(DSNDCP, LOGL_DEBUG, " p1t=%i;\n",
+ comp_field->v44_params->p1t);
+ LOGP(DSNDCP, LOGL_DEBUG, " p1r=%i;\n",
+ comp_field->v44_params->p1r);
+ LOGP(DSNDCP, LOGL_DEBUG, " p3t=%i;\n",
+ comp_field->v44_params->p3t);
+ LOGP(DSNDCP, LOGL_DEBUG, " p3r=%i;\n",
+ comp_field->v44_params->p3r);
+ LOGP(DSNDCP, LOGL_DEBUG, " }\n");
+ break;
+ }
+ }
+
+ LOGP(DSNDCP, LOGL_DEBUG, "}\n");
+ LOGP(DSNDCP, LOGL_DEBUG, "\n");
+ }
+
+}
--
To view, visit https://gerrit.osmocom.org/641
To unsubscribe, visit https://gerrit.osmocom.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: If2d63fe2550864cafef3156b1dc0629037c49c1e
Gerrit-PatchSet: 1
Gerrit-Project: openbsc
Gerrit-Branch: master
Gerrit-Owner: dexter <pmaier at sysmocom.de>