[PATCH] openbsc[master]: Added code to control GPRS TCP/IP header compression.

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
Mon Aug 1 15:51:46 UTC 2016


Review at  https://gerrit.osmocom.org/642

Added code to control GPRS TCP/IP header compression.

In this commit two modules were added:

gprs_sndcp_comp_entity.h/c: This part handles the creation and
destruction of conpression entites. It handles the allocation
and freeing of the memory and offers functions to query
compression parameters (i.e. which compression entity should
be used if a packet from NSAPI x has to be compressed?)

gprs_sndcp_hdrcomp.c/h: This is the code that performs the
actual header compression. It takes care that the packets are
compressed/decompressed with the right modes etc.

It works, but is not yet ready for merging. Both files depend
on each other so that they only can be merged both at the same
time.

Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43
---
M openbsc/include/openbsc/Makefile.am
A openbsc/include/openbsc/gprs_sndcp_comp_entity.h
A openbsc/include/openbsc/gprs_sndcp_hdrcomp.h
M openbsc/src/gprs/Makefile.am
A openbsc/src/gprs/gprs_sndcp_comp_entity.c
A openbsc/src/gprs/gprs_sndcp_hdrcomp.c
6 files changed, 1,017 insertions(+), 2 deletions(-)


  git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/42/642/1

diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am
index b37103f..e159db5 100644
--- a/openbsc/include/openbsc/Makefile.am
+++ b/openbsc/include/openbsc/Makefile.am
@@ -18,7 +18,8 @@
 		 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 gprs_sndcp_xid.h
+		 gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h gprs_sndcp_xid.h \
+		gprs_sndcp_comp_entity.h gprs_sndcp_hdrcomp.h
 
 openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h
 openbscdir = $(includedir)/openbsc
diff --git a/openbsc/include/openbsc/gprs_sndcp_comp_entity.h b/openbsc/include/openbsc/gprs_sndcp_comp_entity.h
new file mode 100644
index 0000000..677b82d
--- /dev/null
+++ b/openbsc/include/openbsc/gprs_sndcp_comp_entity.h
@@ -0,0 +1,91 @@
+/* GPRS SNDCP header compression entity management tools */
+
+/* (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/>.
+ *
+ */
+
+#ifndef _GPRS_SNDCP_COMP_ENTITY_H
+#define _GPRS_SNDCP_COMP_ENTITY_H
+
+#include <stdint.h>
+#include <osmocom/core/linuxlist.h>
+#include <openbsc/gprs_sndcp_xid.h>
+
+/* Header / Data compression entity */
+struct gprs_sndcp_comp_entity
+{
+	struct llist_head list;
+
+	/* Serves as an ID in case we want to delete this entity later */
+	int entity;		/* see also: 6.5.1.1.3 and 6.6.1.1.3 */
+
+	/* Specifies to which NSAPIs the compression entity is assigned */
+	int nsapi_len;		/* Number of applicable NSAPIs (default 0) */
+	int nsapi[11];		/* Applicable NSAPIs (default 0) */
+
+	/* Assigned pcomp values */
+	int comp_len;		/* Number of contained PCOMP / DCOMP values */
+	int comp[16];		/* see also: 6.5.1.1.5 and 6.6.1.1.5 */
+
+	/* Algorithm parameters */
+	int algo;		/* Algorithm type (see gprs_sndcp_xid.h) */
+	int compclass;		/* See gprs_sndcp_xid.h/c */
+	void *status;		/* Algorithm status and parameters */
+};
+
+/* Free a list with compression entities */
+void gprs_sndcp_comp_entities_free (struct llist_head *comp_entities);
+
+/* Delete a compression entity */
+void gprs_sndcp_comp_entities_delete (struct llist_head *comp_entities,
+				      int entity);
+
+/* Create and Add a new compression entity
+(returns a pointer to the compression entity that has just been created) */
+struct gprs_sndcp_comp_entity *
+gprs_sndcp_comp_entities_add (struct llist_head *comp_entities,
+			      struct gprs_sndcp_comp_field *comp_field);
+
+/* Find compression entity by its entity number */
+struct gprs_sndcp_comp_entity *
+gprs_sndcp_comp_entity_find_by_entity (struct llist_head*comp_entities,
+				       int entity);
+
+/* Find which compression entity handles the specified pcomp/dcomp */
+struct gprs_sndcp_comp_entity *
+gprs_sndcp_comp_entity_find_by_comp (struct llist_head *comp_entities,
+				     int comp);
+
+/* Find which compression entity handles the specified nsapi */
+struct gprs_sndcp_comp_entity *
+gprs_sndcp_comp_entity_find_by_nsapi (struct llist_head *comp_entities,
+				      int nsapi);
+
+/* Find a comp_index for a given pcomp/dcomp value */
+int 
+gprs_sndcp_comp_entity_find_comp_index_by_comp (struct gprs_sndcp_comp_entity
+						*comp_entity, int comp);
+
+/* Find a pcomp/dcomp value for a given comp_index */
+int 
+gprs_sndcp_comp_entity_find_comp_by_comp_index (struct gprs_sndcp_comp_entity
+						*comp_entity,
+						int comp_index);
+
+#endif
diff --git a/openbsc/include/openbsc/gprs_sndcp_hdrcomp.h b/openbsc/include/openbsc/gprs_sndcp_hdrcomp.h
new file mode 100644
index 0000000..e73bad1
--- /dev/null
+++ b/openbsc/include/openbsc/gprs_sndcp_hdrcomp.h
@@ -0,0 +1,68 @@
+/* GPRS SNDCP header compression handler */
+
+/* (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/>.
+ *
+ */
+
+#ifndef _GPRS_SNDCP_HDRCOMP_H
+#define _GPRS_SNDCP_HDRCOMP_H
+
+#include <stdint.h>
+#include <osmocom/core/linuxlist.h>
+#include <openbsc/gprs_sndcp_comp_entity.h>
+
+/* 1=Bypass any header compression, 0=Normal */
+#define GPRS_SNDCP_HDRCOMP_BYPASS 0	
+
+/* Header compression entity */
+struct gprs_sndcp_hdrcomp_compression_entity {
+
+	/* Specifies to which NSAPIs the compression entity is assigned */
+	int nsapi_len;		/* Number of applicable NSAPIs (default 0) */
+	int nsapi[11];		/* Applicable NSAPIs (default 0) */
+
+	/* Assigned pcomp values */
+	int pcomp_len;		/* Number of contained PCOMP / DCOMP values */
+	int pcomp[16];		/* see also: 6.5.1.1.5 and 6.6.1.1.5 */
+
+	/* Algorithm parameters */
+	int compclass;		/* 1=Header compression, 2=Data compression */
+	int algo;		/* Algorithm type (see gprs_sndcp_xid.h) */
+	void *status;		/* Algorithm status and parameters */
+};
+
+
+/* Initalize header compression */
+int gprs_sndcp_hdrcomp_init(struct gprs_sndcp_comp_entity *comp_entity,
+			    struct gprs_sndcp_comp_field *comp_field);
+
+/* Terminate header compression */
+void gprs_sndcp_hdrcomp_term(struct gprs_sndcp_comp_entity *comp_entity);
+
+/* Expand header compressed packet */
+int gprs_sndcp_hdrcomp_expand(uint8_t * packet, int packet_len, int pcomp,
+			      struct llist_head *comp_entities);
+
+/* Expand header compressed packet */
+int gprs_sndcp_hdrcomp_compress(uint8_t * packet, int packet_len,
+				int *pcomp,
+				struct llist_head *comp_entities,
+				int nsapi);
+
+#endif
diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am
index 67e9943..3d6c82a 100644
--- a/openbsc/src/gprs/Makefile.am
+++ b/openbsc/src/gprs/Makefile.am
@@ -21,7 +21,8 @@
 			$(OSMO_LIBS) $(LIBCRYPTO_LIBS) -lrt
 
 osmo_sgsn_SOURCES =	gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \
-			slhc.c gprs_sndcp_xid.c  \
+			slhc.c gprs_sndcp_xid.c gprs_sndcp_comp_entity.c \
+			gprs_sndcp_hdrcomp.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 \
diff --git a/openbsc/src/gprs/gprs_sndcp_comp_entity.c b/openbsc/src/gprs/gprs_sndcp_comp_entity.c
new file mode 100644
index 0000000..380b2f0
--- /dev/null
+++ b/openbsc/src/gprs/gprs_sndcp_comp_entity.c
@@ -0,0 +1,331 @@
+/* GPRS SNDCP header compression entity management tools */
+
+/* (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/linuxlist.h>
+#include <osmocom/core/talloc.h>
+
+#include <openbsc/debug.h>
+#include <openbsc/gprs_sndcp_xid.h>
+#include <openbsc/gprs_sndcp_comp_entity.h>
+#include <openbsc/gprs_sndcp_hdrcomp.h>
+
+/* Create a new compression entity from a XID-Field */
+static struct gprs_sndcp_comp_entity *
+gprs_sndcp_comp_entity_create (struct gprs_sndcp_comp_field *comp_field)
+{
+	struct gprs_sndcp_comp_entity *comp_entity;
+	comp_entity = talloc_zero (NULL, struct gprs_sndcp_comp_entity);
+
+	/* Copy relevant information from the SNDCP-XID field */
+	comp_entity->entity = comp_field->entity;
+	comp_entity->comp_len = comp_field->comp_len;
+	memcpy (comp_entity->comp, comp_field->comp,
+		comp_field->comp_len * sizeof (int));
+
+	if (comp_field->rfc1144_params) {
+		comp_entity->nsapi_len =
+			comp_field->rfc1144_params->nsapi_len;
+		memcpy (comp_entity->nsapi,
+			comp_field->rfc1144_params->nsapi,
+			comp_entity->nsapi_len * sizeof (int));
+	}
+	else if (comp_field->rfc2507_params) {
+		comp_entity->nsapi_len =
+			comp_field->rfc2507_params->nsapi_len;
+		memcpy (comp_entity->nsapi,
+			comp_field->rfc2507_params->nsapi,
+			comp_entity->nsapi_len * sizeof (int));
+	}
+	else if (comp_field->rohc_params) {
+		comp_entity->nsapi_len = comp_field->rohc_params->nsapi_len;
+		memcpy (comp_entity->nsapi, comp_field->rohc_params->nsapi,
+			comp_entity->nsapi_len * sizeof (int));
+	}
+	else if (comp_field->v42bis_params) {
+		comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len;
+		memcpy (comp_entity->nsapi,
+			comp_field->v42bis_params->nsapi,
+			comp_entity->nsapi_len * sizeof (int));
+	}
+	else if (comp_field->v44_params) {
+		comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len;
+		memcpy (comp_entity->nsapi,
+			comp_field->v42bis_params->nsapi,
+			comp_entity->nsapi_len * sizeof (int));
+	}
+	else {
+		talloc_free (comp_entity);
+		LOGP (DSNDCP, LOGL_ERROR,
+		      "Comp field contained invalid parameters, compression entity not created!\n");
+		return NULL;
+	}
+
+	comp_entity->algo = comp_field->algo;
+	comp_entity->status = NULL;
+
+	/* Determine of which class our compression entity will be 
+	   (Protocol or Data compresson ?) */
+	comp_entity->compclass =
+		gprs_sndcp_get_compression_class (comp_field);
+
+	if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) {
+		if (gprs_sndcp_hdrcomp_init (comp_entity, comp_field) == 0)
+			LOGP (DSNDCP, LOGL_INFO,
+			      "New header compression entity (%i) created.\n",
+			      comp_entity->entity);
+		else {
+			talloc_free (comp_entity);
+			LOGP (DSNDCP, LOGL_ERROR,
+			      "Header compression entity (%i) creation failed!\n",
+			      comp_entity->entity);
+			return NULL;
+		}
+	}
+	else
+		LOGP (DSNDCP, LOGL_INFO,
+		      "New data compression entity (%i) created.\n",
+		      comp_entity->entity);
+
+	return comp_entity;
+}
+
+/* Free a list with compression entities */
+void
+gprs_sndcp_comp_entities_free (struct llist_head *comp_entities)
+{
+	if (comp_entities) {
+		struct gprs_sndcp_comp_entity *comp_entity;
+
+		llist_for_each_entry (comp_entity, comp_entities, list) {
+			/* Free compression entity */
+			if (comp_entity->compclass ==
+			    SNDCP_XID_PROTOCOL_COMPRESSION) {
+				LOGP (DSNDCP, LOGL_INFO,
+				      "Deleting (free) header compression entity %i ...\n",
+				      comp_entity->entity);
+				gprs_sndcp_hdrcomp_term (comp_entity);
+			}
+			else
+				LOGP (DSNDCP, LOGL_INFO,
+				      "Deleting (free) data compression entity %i ...\n",
+				      comp_entity->entity);
+
+			talloc_free (comp_entity);
+		}
+
+	}
+}
+
+/* Delete a compression entity */
+void
+gprs_sndcp_comp_entities_delete (struct llist_head *comp_entities, int entity)
+{
+	struct gprs_sndcp_comp_entity *comp_entity;
+	struct gprs_sndcp_comp_entity *comp_entity_to_delete = NULL;
+
+	if (comp_entities) {
+
+		llist_for_each_entry (comp_entity, comp_entities, list) {
+			if (comp_entity->entity == entity)
+				comp_entity_to_delete = comp_entity;
+		}
+
+		if (comp_entity_to_delete) {
+			if (comp_entity_to_delete->compclass ==
+			    SNDCP_XID_PROTOCOL_COMPRESSION) {
+				LOGP (DSNDCP, LOGL_INFO,
+				      "Deleting header compression entity %i ...\n",
+				      comp_entity_to_delete->entity);
+				gprs_sndcp_hdrcomp_term
+					(comp_entity_to_delete);
+			}
+			else
+				LOGP (DSNDCP, LOGL_INFO,
+				      "Deleting data compression entity %i ...\n",
+				      comp_entity_to_delete->entity);
+
+			/* Delete compression entity */
+			llist_del (&comp_entity_to_delete->list);
+			talloc_free (comp_entity_to_delete);
+		}
+	}
+}
+
+/* Create and Add a new compression entity
+(returns a pointer to the compression entity that has just been created) */
+struct gprs_sndcp_comp_entity *
+gprs_sndcp_comp_entities_add (struct
+			      llist_head
+			      *comp_entities, struct
+			      gprs_sndcp_comp_field *comp_field)
+{
+	struct gprs_sndcp_comp_entity *comp_entity;
+
+	/* Just to be sure, if the entity is already in
+	   the list it will be deleted now */
+	gprs_sndcp_comp_entities_delete (comp_entities, comp_field->entity);
+
+	/* Create and add a new entity to the list */
+	comp_entity = gprs_sndcp_comp_entity_create (comp_field);
+
+	if (comp_entity) {
+		llist_add (&comp_entity->list, comp_entities);
+		return comp_entity;
+	}
+
+	return NULL;
+}
+
+/* Find compression entity by its entity number */
+struct gprs_sndcp_comp_entity *
+gprs_sndcp_comp_entity_find_by_entity (struct
+				       llist_head *comp_entities, int entity)
+{
+	struct gprs_sndcp_comp_entity *comp_entity;
+
+	if (comp_entities) {
+		llist_for_each_entry (comp_entity, comp_entities, list) {
+			if (comp_entity->entity == entity)
+				return comp_entity;
+		}
+	}
+
+	LOGP (DSNDCP, LOGL_ERROR,
+	      "Could not find a matching compression entity for given entity number %i.\n",
+	      entity);
+	return NULL;
+}
+
+/* Find which compression entity handles the specified pcomp/dcomp */
+struct gprs_sndcp_comp_entity *
+gprs_sndcp_comp_entity_find_by_comp (struct
+				     llist_head *comp_entities, int comp)
+{
+	struct gprs_sndcp_comp_entity *comp_entity;
+	int i;
+
+	if (comp_entities) {
+		llist_for_each_entry (comp_entity, comp_entities, list) {
+			for (i = 0; i < comp_entity->comp_len; i++) {
+				if (comp_entity->comp[i] == comp)
+					return comp_entity;
+			}
+		}
+	}
+
+	LOGP (DSNDCP, LOGL_ERROR,
+	      "Could not find a matching compression entity for given pcomp/dcomp value %i.\n",
+	      comp);
+	return NULL;
+}
+
+/* Find which compression entity handles the specified nsapi */
+struct gprs_sndcp_comp_entity *
+gprs_sndcp_comp_entity_find_by_nsapi (struct
+				      llist_head *comp_entities, int nsapi)
+{
+	struct gprs_sndcp_comp_entity *comp_entity;
+	int i;
+
+	if (comp_entities) {
+		llist_for_each_entry (comp_entity, comp_entities, list) {
+			for (i = 0; i < comp_entity->nsapi_len; i++) {
+				if (comp_entity->nsapi[i] == nsapi)
+					return comp_entity;
+			}
+		}
+
+		LOGP (DSNDCP, LOGL_ERROR,
+		      "Could not find a matching compression entity for given nsapi value %i\n",
+		      nsapi);
+		return NULL;
+	}
+
+	LOGP (DSNDCP, LOGL_ERROR,
+	      "Compression entity list contained null-pointer!\n");
+	return NULL;
+}
+
+/* Find a comp_index for a given pcomp/dcomp value */
+int
+gprs_sndcp_comp_entity_find_comp_index_by_comp (struct
+						gprs_sndcp_comp_entity
+						*comp_entity, int comp)
+{
+	int i;
+
+	if (comp_entity) {
+		/* A pcomp/dcomp field set to zero always disables
+		   all sort of compression and is assigned fix. So we
+		   just return zero in this case */
+		if (comp == 0)
+			return 0;
+
+		/* Look in the pcomp/dcomp list for the index */
+		for (i = 0; i < comp_entity->comp_len; i++) {
+			if (comp_entity->comp[i] == comp)
+				return i + 1;
+		}
+
+		LOGP (DSNDCP, LOGL_ERROR,
+		      "Could not find a matching comp_index for given pcomp/dcomp value %i\n",
+		      comp);
+		return 0;
+	}
+
+	LOGP (DSNDCP, LOGL_ERROR,
+	      "Compression entity contained null-pointer!\n");
+	return 0;
+}
+
+/* Find a pcomp/dcomp value for a given comp_index */
+int
+gprs_sndcp_comp_entity_find_comp_by_comp_index (struct
+						gprs_sndcp_comp_entity
+						*comp_entity, int comp_index)
+{
+	if (comp_entity) {
+		/* A comp_index of zero translates to zero right away. */
+		if (comp_index == 0)
+			return 0;
+
+		if (comp_index > comp_entity->comp_len) {
+			LOGP (DSNDCP, LOGL_ERROR,
+			      "Could not find a matching pcomp/dcomp value for given comp_index value %i.\n",
+			      comp_index);
+			return 0;
+		}
+
+		/* Look in the pcomp/dcomp list for the comp_index */
+		return comp_entity->comp[comp_index - 1];
+	}
+
+	LOGP (DSNDCP, LOGL_ERROR,
+	      "Compression entity contained null-pointer!\n");
+	return 0;
+}
diff --git a/openbsc/src/gprs/gprs_sndcp_hdrcomp.c b/openbsc/src/gprs/gprs_sndcp_hdrcomp.c
new file mode 100644
index 0000000..8796684
--- /dev/null
+++ b/openbsc/src/gprs/gprs_sndcp_hdrcomp.c
@@ -0,0 +1,523 @@
+/* GPRS SNDCP header compression handler */
+
+/* (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/gprs_llc.h>
+#include <openbsc/sgsn.h>
+#include <openbsc/gprs_sndcp_xid.h>
+#include <openbsc/slhc.h>
+#include <openbsc/debug.h>
+#include <openbsc/gprs_sndcp_comp_entity.h>
+#include <openbsc/gprs_sndcp_hdrcomp.h>
+
+/* Enable private debug messages */
+#define GPRS_SNDCP_HDRCOMP_DEBUG 1
+
+/* Test RFC1144 implementation 
+   (Caution: GPRS_SNDCP_HDRCOMP_BYPASS in .h file has to be set to 1!) */
+#define GPRS_SNDCP_HDRCOMP_RFC1144_TEST 0
+
+/* Exit immediately in case of RFC1144 test failure */
+#define GPRS_SNDCP_HDRCOMP_RFC1144_TEST_EXITONERR 1
+
+/* For debug/test only! */
+#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST == 1
+static struct slcompress *test_compression_state_tx = NULL;
+static struct slcompress *test_compression_state_rx = NULL;
+static int test_errors = 0;
+static int gprs_sndcp_hdrcomp_test_ind(uint8_t * packet, int packet_len);
+static int gprs_sndcp_hdrcomp_test_req(uint8_t * packet, int packet_len);
+#endif
+
+
+/* Initalize header compression */
+int gprs_sndcp_hdrcomp_init(struct gprs_sndcp_comp_entity *comp_entity,
+			    struct gprs_sndcp_comp_field *comp_field)
+{
+	/* Note: This function is automatically called from
+		 gprs_sndcp_comp_entity.c when a new header compression
+		 entity is created by gprs_sndcp.c */
+
+	if ((comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION)
+	    && (comp_entity->algo == RFC_1144)) {
+		comp_entity->status =
+		    slhc_init(comp_field->rfc1144_params->s01 + 1,
+			      comp_field->rfc1144_params->s01 + 1);
+		LOGP(DSNDCP, LOGL_INFO,
+		     "RFC1144 header compression initalized.\n");
+		return 0;
+	}
+
+	/* Just in case someone tries to initalize an unknown or unsupported
+	   header compresson. Since everything is checked during the SNDCP
+	   negotiation process, this should never happen! */
+	LOGP(DSNDCP, LOGL_ERROR,
+	     "Unknown or unsupported header compression type requested for initalization, could not initalize...\n");
+	return -EINVAL;
+
+}
+
+
+/* Terminate header compression */
+void gprs_sndcp_hdrcomp_term(struct gprs_sndcp_comp_entity *comp_entity)
+{
+	/* Note: This function is automatically called from
+	   gprs_sndcp_comp_entity.c when a header compression
+	   entity is deleted by gprs_sndcp.c */
+
+	if ((comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION)
+	    && (comp_entity->algo == RFC_1144)) {
+		if (comp_entity->status) {
+			slhc_free((struct slcompress *) comp_entity->
+				  status);
+			comp_entity->status = NULL;
+		}
+		LOGP(DSNDCP, LOGL_INFO,
+		     "RFC1144 header compression terminated.\n");
+		return;
+	}
+
+	/* Just in case someone tries to initalize an unknown or unsupported
+	   header compresson. Since everything is checked during the SNDCP
+	   negotiation process, this should never happen! */
+	LOGP(DSNDCP, LOGL_ERROR,
+	     "Unknown or unsupported header compression type requested for termiation, could not initalize...\n");
+}
+
+
+/* Display compressor status */
+static void gprs_sndcp_hdrcomp_rfc1144_stat(struct slcompress *comp)
+{
+	slhc_i_status(comp);
+	slhc_o_status(comp);
+}
+
+
+/* Compress a packet using Van Jacobson RFC1144 header compression */
+static int gprs_sndcp_hdrcomp_rfc1144_compress(struct slcompress *comp,
+					       uint8_t * packet,
+					       int packet_len,
+					       int *pcomp_index)
+{
+	uint8_t *packet_compressed;
+	uint8_t *packet_compressed_ptr;	/* Not used */
+	int packet_compressed_len;
+
+	/* Reserve some space for to store the compression result */
+	packet_compressed = talloc_zero_size(NULL, packet_len);
+
+	/* Run compressor */
+	memcpy(packet_compressed, packet, packet_len);
+	packet_compressed_len =
+	    slhc_compress(comp, packet, packet_len,
+			  (uint8_t *) packet_compressed,
+			  &packet_compressed_ptr, 0);
+
+	/* Copy back compression result */
+	memcpy(packet, packet_compressed, packet_len);
+	talloc_free(packet_compressed);
+
+	/* Generate pcomp_index */
+	if ((packet[0] & SL_TYPE_COMPRESSED_TCP) == SL_TYPE_COMPRESSED_TCP) {
+		*pcomp_index = 2;
+		/* Remove tag for compressed TCP, because the packet
+		   type is already define by pcomp */
+		//      packet[0] &= 0x7F;      
+	} else if ((packet[0] & SL_TYPE_UNCOMPRESSED_TCP) ==
+		   SL_TYPE_UNCOMPRESSED_TCP) {
+		*pcomp_index = 1;
+
+		/* Remove tag for uncompressed TCP, because the
+		   packet type is already define by pcomp */
+		packet[0] &= 0x4F;	
+	} else
+		*pcomp_index = 0;
+
+	return packet_compressed_len;
+}
+
+/* Expand a packet using Van Jacobson RFC1144 header compression */
+static int gprs_sndcp_hdrcomp_rfc1144_expand(struct slcompress *comp,
+					     uint8_t * packet,
+					     int packet_len,
+					     int pcomp_index)
+{
+	int packet_decompressed_len;
+	int type = -1;
+
+	/* Note: this function should never be called with pcomp_index=0,
+	   since this condition is already filtered
+	   out by gprs_sndcp_hdrcomp_expand() */
+
+	/* Determine the packet type by the PCOMP index */
+	switch (pcomp_index) {
+	case 1:
+		type = SL_TYPE_UNCOMPRESSED_TCP;
+		break;
+	case 2:
+		type = SL_TYPE_COMPRESSED_TCP;
+		break;
+	}
+
+	/* Restore the original version nibble on
+	   marked uncompressed packets */
+	if (type == SL_TYPE_UNCOMPRESSED_TCP) {
+		LOGP(DSNDCP, LOGL_INFO,
+		     "Uncompressed rfc1144 packet received...\n");
+
+
+		/* Just in case the phone tags uncompressed tcp-packets
+		   (normally this is handled by pcomp so there is
+		   no need for tagging the packets) */
+		packet[0] &= 0x4F;
+		packet_decompressed_len =
+		    slhc_remember(comp, packet, packet_len);
+		return packet_decompressed_len;
+	}
+
+	/* Uncompress compressed packets */
+	else if (type == SL_TYPE_COMPRESSED_TCP) {
+		LOGP(DSNDCP, LOGL_INFO,
+		     "Compressed rfc1144 packet received...\n");
+		packet_decompressed_len =
+		    slhc_uncompress(comp, packet, packet_len);
+		return packet_decompressed_len;
+	}
+
+
+	/* Regular or unknown packets will not be touched */
+	return packet_len;
+}
+
+
+/* Expand header compressed packet */
+int gprs_sndcp_hdrcomp_expand(uint8_t * packet, int packet_len, int pcomp,
+			      struct llist_head *comp_entities)
+{
+	int rc;
+	int pcomp_index = 0;
+	struct gprs_sndcp_comp_entity *comp_entity;
+
+	/* Skip on pcomp=0 */
+	if (pcomp == 0) {
+		LOGP(DSNDCP, LOGL_INFO,
+		     "Uncompressed packet received (pcomp=0), skipping compression...\n");
+		return packet_len;
+	}
+
+	/* Find out which compression entity handles the packet */
+	comp_entity =
+	    gprs_sndcp_comp_entity_find_by_comp(comp_entities, pcomp);
+
+	/* Skip compression if no suitable compression entity can be found! */
+	if (comp_entity == NULL) {
+		LOGP(DSNDCP, LOGL_ERROR,
+		     "Compressed packet received (pcomp=%i) but no suitable compression entity found, skipping compression...\n",
+		     pcomp);
+		return packet_len;
+	}
+
+	/* Find pcomp_index */
+	pcomp_index =
+	    gprs_sndcp_comp_entity_find_comp_index_by_comp(comp_entity,
+							   pcomp);
+
+#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST == 1
+	/* Test mode */
+	LOGP(DSNDCP, LOGL_INFO,
+	     "gprs_sndcp_hdrcomp_expand(): testing compression...!\n");
+	rc = gprs_sndcp_hdrcomp_test_ind(packet, packet_len);
+#else
+	/* Normal operation: */
+	rc = gprs_sndcp_hdrcomp_rfc1144_expand((struct slcompress *)
+					       comp_entity->status, packet,
+					       packet_len, pcomp_index);
+	gprs_sndcp_hdrcomp_rfc1144_stat((struct slcompress *) comp_entity->
+					status);
+#endif
+
+	LOGP(DSNDCP, LOGL_DEBUG,
+	     "Header expansion done, old length=%i, new length=%i, pcomp=%i, pcomp_index=%i\n",
+	     packet_len, rc, pcomp, pcomp_index);
+	return rc;
+}
+
+
+/* Expand header compressed packet */
+int gprs_sndcp_hdrcomp_compress(uint8_t * packet, int packet_len,
+				int *pcomp,
+				struct llist_head *comp_entities,
+				int nsapi)
+{
+	int rc;
+	int pcomp_index = 0;
+	struct gprs_sndcp_comp_entity *comp_entity;
+
+	/* Find out which compression entity handles the packet */
+	comp_entity =
+	    gprs_sndcp_comp_entity_find_by_nsapi(comp_entities, nsapi);
+
+	/* Skip compression if no suitable compression entity can be found! */
+	if (comp_entity == NULL) {
+		LOGP(DSNDCP, LOGL_INFO,
+		     "No suitable compression entity found for nsapi %i, skipping compression...\n",
+		     nsapi);
+		*pcomp = 0;
+		return packet_len;
+	}
+#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST == 1
+	LOGP(DSNDCP, LOGL_INFO,
+	     "gprs_sndcp_hdrcomp_expand(): testing compression...!\n");
+	rc = gprs_sndcp_hdrcomp_test_req(packet, packet_len);
+	*pcomp = 0;
+	return rc;
+#else
+	/* Normal operation: */
+	rc = gprs_sndcp_hdrcomp_rfc1144_compress((struct slcompress *)
+						 comp_entity->status,
+						 packet, packet_len,
+						 &pcomp_index);
+	gprs_sndcp_hdrcomp_rfc1144_stat((struct slcompress *) comp_entity->
+					status);
+#endif
+
+	/* Find pcomp value */
+	*pcomp =
+	    gprs_sndcp_comp_entity_find_comp_by_comp_index(comp_entity,
+							   pcomp_index);
+
+	LOGP(DSNDCP, LOGL_DEBUG,
+	     "Header compression done, old length=%i, new length=%i, pcomp=%i, pcomp_index=%i\n",
+	     packet_len, rc, *pcomp, pcomp_index);
+	return rc;
+}
+
+
+
+
+
+
+
+#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST == 1
+
+/* 
+ * This is a test implementation to make sure the rfc1144 compression
+ * implementation works as expected. All data is first compressed and
+ * decompressed on both directions. 
+ */
+
+/* FIXME: FOR EXPERIMENTATION ONLY! REMOVE AS SOON AS POSSIBLE */
+static uint16_t header_checksum(uint8_t * iph, unsigned int ihl)
+{
+	int i;
+	uint16_t temp;
+	uint32_t accumulator = 0xFFFF;
+
+	for (i = 0; i < ihl * 2; i++) {
+		temp = ((*iph) << 8) & 0xFF00;
+		iph++;
+		temp |= (*iph) & 0xFF;
+		iph++;
+
+		accumulator += temp;
+		if (accumulator > 0xFFFF) {
+			accumulator++;
+			accumulator &= 0xFFFF;
+		}
+	}
+
+	return (uint16_t) (htons(~accumulator) & 0xFFFF);
+}
+
+/* Check packet integrity */
+static int gprs_sndcp_hdrcomp_test_check_packet(uint8_t * packet,
+						uint8_t * packet_backup,
+						int packet_len,
+						int
+						packet_len_uncompressed)
+{
+	uint16_t checksum;
+
+	if (packet_len != packet_len_uncompressed) {
+		LOGP(DSNDCP, LOGL_INFO,
+		     "prs_sndcp_hdrcomp_test_check_packet(): Error: Packet length mismatch!\n");
+#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST_EXITONERR == 1
+		exit(1);
+#endif
+		return -1;
+	}
+
+	/* Check packet integrety */
+	if (memcmp(packet, packet_backup, packet_len)) {
+		LOGP(DSNDCP, LOGL_INFO,
+		     "prs_sndcp_hdrcomp_test_check_packet(): Warning: Packet content!\n");
+		LOGP(DSNDCP, LOGL_INFO,
+		     "prs_sndcp_hdrcomp_test_check_packet(): %s\n",
+		     osmo_hexdump_nospc(packet_backup, 80));
+		LOGP(DSNDCP, LOGL_INFO,
+		     "prs_sndcp_hdrcomp_test_check_packet(): %s\n",
+		     osmo_hexdump_nospc(packet, 80));
+
+		checksum = header_checksum(packet, 5);
+		LOGP(DSNDCP, LOGL_INFO,
+		     "prs_sndcp_hdrcomp_test_check_packet():  %04x\n",
+		     checksum);
+
+		if (checksum == 0x0000) {
+			LOGP(DSNDCP, LOGL_INFO,
+			     "prs_sndcp_hdrcomp_test_check_packet(): Checksum looks good!\n");
+
+			if (memcmp
+			    (packet + 20, packet_backup + 20,
+			     packet_len - 20))
+				test_errors++;
+			else
+				LOGP(DSNDCP, LOGL_INFO,
+				     "prs_sndcp_hdrcomp_test_check_packet(): Packet looks also good!\n");
+		} else {
+			test_errors++;
+#if GPRS_SNDCP_HDRCOMP_RFC1144_TEST_EXITONERR == 1
+			exit(1);
+#endif
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+/* FIXME: FOR EXPERIMENTATION ONLY! REMOVE AS SOON AS POSSIBLE */
+static int gprs_sndcp_hdrcomp_test_ind(uint8_t * packet, int packet_len)
+{
+	int packet_len_compressed;
+	int packet_len_uncompressed;
+	int pcomp;
+	uint8_t *packet_backup;
+
+	if (test_compression_state_tx == NULL)
+		test_compression_state_tx = slhc_init(8, 8);
+	if (test_compression_state_rx == NULL)
+		test_compression_state_rx = slhc_init(8, 8);
+
+	LOGP(DSNDCP, LOGL_INFO,
+	     "gprs_sndcp_hdrcomp_test_ind(): packet_len=%i\n", packet_len);
+	packet_backup = talloc_zero_size(NULL, packet_len);
+	memcpy(packet_backup, packet, packet_len);
+
+	LOGP(DSNDCP, LOGL_INFO,
+	     "gprs_sndcp_hdrcomp_test_ind(): IND:          %s\n",
+	     osmo_hexdump_nospc(packet, packet_len));
+	packet_len_compressed =
+	    gprs_sndcp_hdrcomp_rfc1144_compress(test_compression_state_rx,
+						packet, packet_len,
+						&pcomp);
+	LOGP(DSNDCP, LOGL_INFO,
+	     "gprs_sndcp_hdrcomp_test_ind(): IND (COMP):   %s\n",
+	     osmo_hexdump_nospc(packet, packet_len_compressed));
+	packet_len_uncompressed =
+	    gprs_sndcp_hdrcomp_rfc1144_expand(test_compression_state_tx,
+					      packet,
+					      packet_len_compressed,
+					      pcomp);
+	LOGP(DSNDCP, LOGL_INFO,
+	     "gprs_sndcp_hdrcomp_test_ind(): IND (DECOMP): %s\n",
+	     osmo_hexdump_nospc(packet, packet_len_uncompressed));
+	LOGP(DSNDCP, LOGL_INFO,
+	     "gprs_sndcp_hdrcomp_test_ind(): packet_len=%i   packet_len_compressed=%i   packet_len_uncompressed=%i\n",
+	     packet_len, packet_len_compressed, packet_len_uncompressed);
+
+	gprs_sndcp_hdrcomp_test_check_packet(packet, packet_backup,
+					     packet_len,
+					     packet_len_uncompressed);
+	talloc_free(packet_backup);
+	gprs_sndcp_hdrcomp_rfc1144_stat(test_compression_state_rx);
+	gprs_sndcp_hdrcomp_rfc1144_stat(test_compression_state_tx);
+	LOGP(DSNDCP, LOGL_INFO,
+	     "gprs_sndcp_hdrcomp_test_ind(): Test errors: %i\n",
+	     test_errors);
+	return packet_len;
+}
+
+/* FIXME: FOR EXPERIMENTATION ONLY! REMOVE AS SOON AS POSSIBLE */
+static int gprs_sndcp_hdrcomp_test_req(uint8_t * packet, int packet_len)
+{
+	int packet_len_compressed;
+	int packet_len_uncompressed;
+	int pcomp;
+	uint8_t *packet_backup;
+
+	if (test_compression_state_tx == NULL)
+		test_compression_state_tx = slhc_init(8, 8);
+	if (test_compression_state_rx == NULL)
+		test_compression_state_rx = slhc_init(8, 8);
+
+	LOGP(DSNDCP, LOGL_INFO,
+	     "gprs_sndcp_hdrcomp_test_req(): packet_len=%i\n", packet_len);
+	packet_backup = talloc_zero_size(NULL, packet_len);
+	memcpy(packet_backup, packet, packet_len);
+
+	LOGP(DSNDCP, LOGL_INFO,
+	     "gprs_sndcp_hdrcomp_test_req(): REQ:          %s\n",
+	     osmo_hexdump_nospc(packet, packet_len));
+	packet_len_compressed =
+	    gprs_sndcp_hdrcomp_rfc1144_compress(test_compression_state_tx,
+						packet, packet_len,
+						&pcomp);
+	LOGP(DSNDCP, LOGL_INFO,
+	     "gprs_sndcp_hdrcomp_test_req(): REQ (COMP):   %s\n",
+	     osmo_hexdump_nospc(packet, packet_len_compressed));
+	packet_len_uncompressed =
+	    gprs_sndcp_hdrcomp_rfc1144_expand(test_compression_state_rx,
+					      packet,
+					      packet_len_compressed,
+					      pcomp);
+	LOGP(DSNDCP, LOGL_INFO,
+	     "gprs_sndcp_hdrcomp_test_req(): REQ (DECOMP): %s\n",
+	     osmo_hexdump_nospc(packet, packet_len_uncompressed));
+	LOGP(DSNDCP, LOGL_INFO,
+	     "gprs_sndcp_hdrcomp_test_req(): packet_len=%i   packet_len_compressed=%i   packet_len_uncompressed=%i\n",
+	     packet_len, packet_len_compressed, packet_len_uncompressed);
+
+	gprs_sndcp_hdrcomp_test_check_packet(packet, packet_backup,
+					     packet_len,
+					     packet_len_uncompressed);
+	talloc_free(packet_backup);
+	gprs_sndcp_hdrcomp_rfc1144_stat(test_compression_state_rx);
+	gprs_sndcp_hdrcomp_rfc1144_stat(test_compression_state_tx);
+	LOGP(DSNDCP, LOGL_INFO,
+	     "gprs_sndcp_hdrcomp_test_ind(): Test errors: %i\n",
+	     test_errors);
+	return packet_len;
+}
+
+#endif

-- 
To view, visit https://gerrit.osmocom.org/642
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ia00260dc09978844c2865957b4d43000b78b5e43
Gerrit-PatchSet: 1
Gerrit-Project: openbsc
Gerrit-Branch: master
Gerrit-Owner: dexter <pmaier at sysmocom.de>



More information about the gerrit-log mailing list