[MERGED] openbsc[master]: RFC1144: integration and unit-test

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/.

Harald Welte gerrit-no-reply at lists.osmocom.org
Sat Sep 24 03:18:00 UTC 2016


Harald Welte has submitted this change and it was merged.

Change subject: RFC1144: integration and unit-test
......................................................................


RFC1144: integration and unit-test

The previously pushed slhc implementation has been modified to compile
and function outside of the kernel. Also debug log messages were added
and datatypes ware matched. The implementation is now ready to be used

Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0
---
M openbsc/.gitignore
M openbsc/configure.ac
M openbsc/include/openbsc/Makefile.am
M openbsc/include/openbsc/debug.h
R openbsc/include/openbsc/slhc.h
M openbsc/src/gprs/Makefile.am
M openbsc/src/gprs/sgsn_main.c
M openbsc/src/gprs/slhc.c
M openbsc/tests/Makefile.am
M openbsc/tests/sgsn/Makefile.am
A openbsc/tests/slhc/Makefile.am
A openbsc/tests/slhc/slhc_test.c
A openbsc/tests/slhc/slhc_test.ok
M openbsc/tests/testsuite.at
14 files changed, 543 insertions(+), 88 deletions(-)

Approvals:
  Harald Welte: Looks good to me, approved
  Jenkins Builder: Verified



diff --git a/openbsc/.gitignore b/openbsc/.gitignore
index 8ce3b70..e75b9eb 100644
--- a/openbsc/.gitignore
+++ b/openbsc/.gitignore
@@ -83,6 +83,7 @@
 tests/mm_auth/mm_auth_test
 tests/xid/xid_test
 tests/sndcp_xid/sndcp_xid_test
+tests/slhc/slhc_test
 
 tests/atconfig
 tests/atlocal
diff --git a/openbsc/configure.ac b/openbsc/configure.ac
index 9dc2f8d..cebabdc 100644
--- a/openbsc/configure.ac
+++ b/openbsc/configure.ac
@@ -232,6 +232,7 @@
     tests/mm_auth/Makefile
     tests/xid/Makefile
     tests/sndcp_xid/Makefile
+    tests/slhc/Makefile
     doc/Makefile
     doc/examples/Makefile
     Makefile)
diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am
index a91322f..12e1a66 100644
--- a/openbsc/include/openbsc/Makefile.am
+++ b/openbsc/include/openbsc/Makefile.am
@@ -65,6 +65,7 @@
 	sgsn.h \
 	signal.h \
 	silent_call.h \
+	slhc.h \
 	smpp.h \
 	sms_queue.h \
 	socket.h \
diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h
index 43ebb19..90ddca5 100644
--- a/openbsc/include/openbsc/debug.h
+++ b/openbsc/include/openbsc/debug.h
@@ -29,6 +29,7 @@
 	DBSSGP,
 	DLLC,
 	DSNDCP,
+	DSLHC,
 	DNAT,
 	DCTRL,
 	DSMPP,
diff --git a/openbsc/include/openbsc/slhc_vj.h b/openbsc/include/openbsc/slhc.h
similarity index 97%
rename from openbsc/include/openbsc/slhc_vj.h
rename to openbsc/include/openbsc/slhc.h
index 8716d59..cd5a47c 100644
--- a/openbsc/include/openbsc/slhc_vj.h
+++ b/openbsc/include/openbsc/slhc.h
@@ -171,7 +171,8 @@
 #define NULLSLCOMPR	(struct slcompress *)0
 
 /* In slhc.c: */
-struct slcompress *slhc_init(int rslots, int tslots);
+struct slcompress *slhc_init(const void *ctx, int rslots, int tslots);
+
 void slhc_free(struct slcompress *comp);
 
 int slhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
@@ -180,4 +181,7 @@
 int slhc_remember(struct slcompress *comp, unsigned char *icp, int isize);
 int slhc_toss(struct slcompress *comp);
 
+void slhc_i_status(struct slcompress *comp);
+void slhc_o_status(struct slcompress *comp);
+
 #endif	/* _SLHC_H */
diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am
index 3b58399..06c12d7 100644
--- a/openbsc/src/gprs/Makefile.am
+++ b/openbsc/src/gprs/Makefile.am
@@ -87,6 +87,7 @@
 	gprs_gsup_client.c \
 	sgsn_cdr.c \
 	sgsn_ares.c \
+	slhc.c \
 	oap.c \
 	oap_messages.c \
 	gprs_llc_xid.c \
diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c
index 7d533c0..9f3260d 100644
--- a/openbsc/src/gprs/sgsn_main.c
+++ b/openbsc/src/gprs/sgsn_main.c
@@ -294,6 +294,11 @@
 		.description = "SCCP User Adaptation (SUA)",
 		.enabled = 1, .loglevel = LOGL_DEBUG,
 	},
+	[DSLHC] = {
+		.name = "DSLHC",
+		.description = "RFC1144 TCP/IP Header compression (SLHC)",
+		.enabled = 1, .loglevel = LOGL_DEBUG,
+	},
 };
 
 static const struct log_info gprs_log_info = {
diff --git a/openbsc/src/gprs/slhc.c b/openbsc/src/gprs/slhc.c
index 27ed252..cbdf8db 100644
--- a/openbsc/src/gprs/slhc.c
+++ b/openbsc/src/gprs/slhc.c
@@ -50,61 +50,77 @@
  *	driver code belonging close to PPP and SLIP
  */
 
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <net/slhc_vj.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <arpa/inet.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/talloc.h>
+#include <openbsc/slhc.h>
+#include <openbsc/debug.h>
 
-#ifdef CONFIG_INET
-/* Entire module is for IP only */
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/termios.h>
-#include <linux/in.h>
-#include <linux/fcntl.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <net/ip.h>
-#include <net/protocol.h>
-#include <net/icmp.h>
-#include <net/tcp.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <linux/timer.h>
-#include <asm/uaccess.h>
-#include <net/checksum.h>
-#include <asm/unaligned.h>
+#define ERR_PTR(x) x
+
 
 static unsigned char *encode(unsigned char *cp, unsigned short n);
 static long decode(unsigned char **cpp);
 static unsigned char * put16(unsigned char *cp, unsigned short x);
 static unsigned short pull16(unsigned char **cpp);
 
+/* Replacement for kernel space function ip_fast_csum() */
+static uint16_t ip_fast_csum(uint8_t *iph, 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);
+}
+
+/* Replacement for kernel space function put_unaligned() */
+static void put_unaligned(uint16_t val, void *ptr)
+{
+	memcpy(ptr,&val,sizeof(val));
+}
+
+
 /* Allocate compression data structure
  *	slots must be in range 0 to 255 (zero meaning no compression)
  * Returns pointer to structure or ERR_PTR() on error.
  */
 struct slcompress *
-slhc_init(int rslots, int tslots)
+slhc_init(const void *ctx, int rslots, int tslots)
 {
 	register short i;
 	register struct cstate *ts;
 	struct slcompress *comp;
 
 	if (rslots < 0 || rslots > 255 || tslots < 0 || tslots > 255)
-		return ERR_PTR(-EINVAL);
+		return NULL;
 
-	comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL);
+	comp = (struct slcompress *)talloc_zero_size(ctx,sizeof(struct slcompress));
 	if (! comp)
 		goto out_fail;
 
 	if (rslots > 0) {
 		size_t rsize = rslots * sizeof(struct cstate);
-		comp->rstate = kzalloc(rsize, GFP_KERNEL);
+		comp->rstate = (struct cstate *) talloc_zero_size(ctx, rsize);
 		if (! comp->rstate)
 			goto out_free;
 		comp->rslot_limit = rslots - 1;
@@ -112,7 +128,7 @@
 
 	if (tslots > 0) {
 		size_t tsize = tslots * sizeof(struct cstate);
-		comp->tstate = kzalloc(tsize, GFP_KERNEL);
+		comp->tstate = (struct cstate *) talloc_zero_size(ctx, tsize);
 		if (! comp->tstate)
 			goto out_free2;
 		comp->tslot_limit = tslots - 1;
@@ -141,11 +157,11 @@
 	return comp;
 
 out_free2:
-	kfree(comp->rstate);
+	talloc_free(comp->rstate);
 out_free:
-	kfree(comp);
+	talloc_free(comp);
 out_fail:
-	return ERR_PTR(-ENOMEM);
+	return NULL;
 }
 
 
@@ -153,16 +169,18 @@
 void
 slhc_free(struct slcompress *comp)
 {
+	DEBUGP(DSLHC, "slhc_free(): Freeing compression states...\n");
+
 	if ( comp == NULLSLCOMPR )
 		return;
 
 	if ( comp->tstate != NULLSLSTATE )
-		kfree( comp->tstate );
+		talloc_free(comp->tstate );
 
 	if ( comp->rstate != NULLSLSTATE )
-		kfree( comp->rstate );
+		talloc_free( comp->rstate );
 
-	kfree( comp );
+	talloc_free( comp );
 }
 
 
@@ -187,6 +205,8 @@
 	} else {
 		*cp++ = n;
 	}
+
+	DEBUGP(DSLHC, "encode(): n=%04x\n",n);
 	return cp;
 }
 
@@ -256,6 +276,7 @@
 			comp->sls_o_nontcp++;
 		else
 			comp->sls_o_tcp++;
+		DEBUGP(DSLHC, "slhc_compress(): Not a TCP packat, will not touch...\n");
 		return isize;
 	}
 	/* Extract TCP header */
@@ -271,6 +292,7 @@
 	    ! (th->ack)){
 		/* TCP connection stuff; send as regular IP */
 		comp->sls_o_tcp++;
+		DEBUGP(DSLHC, "slhc_compress(): Packet is part of a TCP connection, will not touch...\n");
 		return isize;
 	}
 	/*
@@ -287,6 +309,9 @@
 	 * states via linear search.  If we don't find a state
 	 * for the datagram, the oldest state is (re-)used.
 	 */
+
+	DEBUGP(DSLHC, "slhc_compress(): Compressible packet detected!\n");
+
 	for ( ; ; ) {
 		if( ip->saddr == cs->cs_ip.saddr
 		 && ip->daddr == cs->cs_ip.daddr
@@ -310,11 +335,14 @@
 	 * state points to the newest and we only need to set
 	 * xmit_oldest to update the lru linkage.
 	 */
+
+	DEBUGP(DSLHC, "slhc_compress(): Header not yet seen, will memorize header for the next turn...\n");
 	comp->sls_o_misses++;
 	comp->xmit_oldest = lcs->cs_this;
 	goto uncompressed;
 
 found:
+		DEBUGP(DSLHC, "slhc_compress(): Header already seen, trying to compress...\n");
 	/*
 	 * Found it -- move to the front on the connection list.
 	 */
@@ -344,6 +372,39 @@
 	 */
 	oth = &cs->cs_tcp;
 
+	/* Display a little more debug information about which of the
+	 * header fields changed unexpectedly */
+	if(ip->version != cs->cs_ip.version)
+		DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->version != cs->cs_ip.version\n");
+	if(ip->ihl != cs->cs_ip.ihl)
+		DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->ihl != cs->cs_ip.ihl\n");
+	if(ip->tos != cs->cs_ip.tos)
+		DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->tos != cs->cs_ip.tos\n");
+	if((ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000)))
+		DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000))\n");
+	if(ip->ttl != cs->cs_ip.ttl)
+		DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->ttl != cs->cs_ip.ttl\n");
+	if(th->doff != cs->cs_tcp.doff)
+		DEBUGP(DSLHC, "slhc_compress(): Unexpected change: th->doff != cs->cs_tcp.doff\n");
+	if(ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) {
+		DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0)\n");
+		DEBUGP(DSLHC, "slhc_compress(): ip->ihl = %i\n", ip->ihl);
+		DEBUGP(DSLHC, "slhc_compress(): ip+1 =          %s\n",
+		       osmo_hexdump_nospc((uint8_t*)(ip+1),((ip->ihl)-5)*4));
+		DEBUGP(DSLHC, "slhc_compress(): Unexpected change: cs->cs_ipopt =  %s\n",
+		       osmo_hexdump_nospc((uint8_t*)(cs->cs_ipopt),((ip->ihl)-5)*4));
+	}
+	if(th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0) {
+		DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)\n");
+		DEBUGP(DSLHC, "slhc_compress(): th->doff = %i\n", th->doff);
+		DEBUGP(DSLHC, "slhc_compress(): th+1 =          %s\n",
+		       osmo_hexdump_nospc((uint8_t*)(th+1),((th->doff)-5)*4));
+		DEBUGP(DSLHC, "slhc_compress(): cs->cs_tcpopt = %s\n",
+		       osmo_hexdump_nospc((uint8_t*)cs->cs_tcpopt,
+					  ((th->doff)-5)*4));
+	}
+
+
 	if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl
 	 || ip->tos != cs->cs_ip.tos
 	 || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000))
@@ -351,6 +412,7 @@
 	 || th->doff != cs->cs_tcp.doff
 	 || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0)
 	 || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){
+		DEBUGP(DSLHC, "slhc_compress(): The header contains unexpected changes, can't compress...\n");
 		goto uncompressed;
 	}
 
@@ -362,6 +424,7 @@
 	 */
 	if(th->urg){
 		deltaS = ntohs(th->urg_ptr);
+		DEBUGP(DSLHC, "slhc_compress(): flag: Urgent Pointer (U) = 1\n");
 		cp = encode(cp,deltaS);
 		changes |= NEW_U;
 	} else if(th->urg_ptr != oth->urg_ptr){
@@ -369,21 +432,29 @@
 		 * implementation should never do this but RFC793
 		 * doesn't prohibit the change so we have to deal
 		 * with it. */
+		DEBUGP(DSLHC, "slhc_compress(): URG not set but urp changed, can't compress...\n");
 		goto uncompressed;
 	}
 	if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){
+		DEBUGP(DSLHC, "slhc_compress(): flag: Delta Window (W) = 1\n");
 		cp = encode(cp,deltaS);
 		changes |= NEW_W;
 	}
 	if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){
-		if(deltaA > 0x0000ffff)
+		if(deltaA > 0x0000ffff)	{
+			DEBUGP(DSLHC, "slhc_compress(): (deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L, can't compress...\n");
 			goto uncompressed;
+		}
+		DEBUGP(DSLHC, "slhc_compress(): flag: Delta Ack (A) = 1\n");
 		cp = encode(cp,deltaA);
 		changes |= NEW_A;
 	}
 	if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){
-		if(deltaS > 0x0000ffff)
+		if(deltaS > 0x0000ffff)	{
+			DEBUGP(DSLHC, "slhc_compress(): (deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L, can't compress...\n");
 			goto uncompressed;
+		}
+		DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1\n");
 		cp = encode(cp,deltaS);
 		changes |= NEW_S;
 	}
@@ -399,17 +470,21 @@
 		if(ip->tot_len != cs->cs_ip.tot_len &&
 		   ntohs(cs->cs_ip.tot_len) == hlen)
 			break;
+		DEBUGP(DSLHC, "slhc_compress(): Retransmitted packet detected, can't compress...\n");
 		goto uncompressed;
 	case SPECIAL_I:
 	case SPECIAL_D:
 		/* actual changes match one of our special case encodings --
 		 * send packet uncompressed.
 		 */
+		DEBUGP(DSLHC, "slhc_compress(): Special case detected, can't compress...\n");
 		goto uncompressed;
 	case NEW_S|NEW_A:
 		if(deltaS == deltaA &&
 		    deltaS == ntohs(cs->cs_ip.tot_len) - hlen){
 			/* special case for echoed terminal traffic */
+			DEBUGP(DSLHC, "slhc_compress(): Special case for echoed terminal traffic detected...\n");
+			DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1, Delta Window (W) = 1, Urgent Pointer (U) = 1\n");
 			changes = SPECIAL_I;
 			cp = new_seq;
 		}
@@ -417,6 +492,8 @@
 	case NEW_S:
 		if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){
 			/* special case for data xfer */
+			DEBUGP(DSLHC, "slhc_compress(): Special case for data xfer detected...\n");
+			DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1, Delta Ack (A) = 1, Delta Window (W) = 1, Urgent Pointer (U) = 1\n");
 			changes = SPECIAL_D;
 			cp = new_seq;
 		}
@@ -424,11 +501,14 @@
 	}
 	deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id);
 	if(deltaS != 1){
+		DEBUGP(DSLHC, "slhc_compress(): flag: Delta IP ID (I) = 1\n");
 		cp = encode(cp,deltaS);
 		changes |= NEW_I;
 	}
-	if(th->psh)
+	if(th->psh) {
+		DEBUGP(DSLHC, "slhc_compress(): flag: Push (P) = 1\n");
 		changes |= TCP_PUSH_BIT;
+	}
 	/* Grab the cksum before we overwrite it below.  Then update our
 	 * state with this packet's header.
 	 */
@@ -445,6 +525,7 @@
 	if(compress_cid == 0 || comp->xmit_current != cs->cs_this){
 		cp = ocp;
 		*cpp = ocp;
+		DEBUGP(DSLHC, "slhc_compress(): flag: Connection number (C) = 1\n");
 		*cp++ = changes | NEW_C;
 		*cp++ = cs->cs_this;
 		comp->xmit_current = cs->cs_this;
@@ -456,6 +537,10 @@
 	*(__sum16 *)cp = csum;
 	cp += 2;
 /* deltaS is now the size of the change section of the compressed header */
+
+	DEBUGP(DSLHC, "slhc_compress(): Delta-list length (deltaS) = %li\n",deltaS);
+	DEBUGP(DSLHC, "slhc_compress(): Original header len (hlen) = %i\n",hlen);
+
 	memcpy(cp,new_seq,deltaS);	/* Write list of deltas */
 	memcpy(cp+deltaS,icp+hlen,isize-hlen);
 	comp->sls_o_compressed++;
@@ -467,6 +552,7 @@
 	 * to use on future compressed packets in the protocol field).
 	 */
 uncompressed:
+	DEBUGP(DSLHC, "slhc_compress(): Packet will be sent uncompressed...\n");
 	memcpy(&cs->cs_ip,ip,20);
 	memcpy(&cs->cs_tcp,th,20);
 	if (ip->ihl > 5)
@@ -538,6 +624,8 @@
 
 	switch(changes & SPECIALS_MASK){
 	case SPECIAL_I:		/* Echoed terminal traffic */
+		DEBUGP(DSLHC, "slhc_uncompress(): Echoed terminal traffic detected\n");
+
 		{
 		register short i;
 		i = ntohs(ip->tot_len) - hdrlen;
@@ -547,11 +635,13 @@
 		break;
 
 	case SPECIAL_D:			/* Unidirectional data */
+		DEBUGP(DSLHC, "slhc_uncompress(): Unidirectional data detected\n");
 		thp->seq = htonl( ntohl(thp->seq) +
 				  ntohs(ip->tot_len) - hdrlen);
 		break;
 
 	default:
+		DEBUGP(DSLHC, "slhc_uncompress(): default packet type detected\n");
 		if(changes & NEW_U){
 			thp->urg = 1;
 			if((x = decode(&cp)) == -1) {
@@ -601,6 +691,7 @@
 	ip->tot_len = htons(len);
 	ip->check = 0;
 
+	DEBUGP(DSLHC, "slhc_uncompress(): making space for the reconstructed header...\n");
 	memmove(icp + hdrlen, cp, len - hdrlen);
 
 	cp = icp;
@@ -625,6 +716,7 @@
 
 	return len;
 bad:
+	DEBUGP(DSLHC, "slhc_uncompress(): bad packet detected!\n");
 	comp->sls_i_error++;
 	return slhc_toss( comp );
 }
@@ -641,6 +733,7 @@
 	if(isize < 20) {
 		/* The packet is shorter than a legal IP header */
 		comp->sls_i_runt++;
+		DEBUGP(DSLHC, "slhc_remember(): The packet is shorter than a legal IP header ==> slhc_toss()\n");
 		return slhc_toss( comp );
 	}
 	/* Peek at the IP header's IHL field to find its length */
@@ -648,6 +741,7 @@
 	if(ihl < 20 / 4){
 		/* The IP header length field is too small */
 		comp->sls_i_runt++;
+		DEBUGP(DSLHC, "slhc_remember(): The IP header length field is too small ==> slhc_toss()\n");
 		return slhc_toss( comp );
 	}
 	index = icp[9];
@@ -656,10 +750,12 @@
 	if (ip_fast_csum(icp, ihl)) {
 		/* Bad IP header checksum; discard */
 		comp->sls_i_badcheck++;
+		DEBUGP(DSLHC, "slhc_remember(): Bad IP header checksum; discard ==> slhc_toss()\n");
 		return slhc_toss( comp );
 	}
 	if(index > comp->rslot_limit) {
 		comp->sls_i_error++;
+		DEBUGP(DSLHC, "slhc_remember(): index > comp->rslot_limit ==> slhc_toss()\n");
 		return slhc_toss(comp);
 	}
 
@@ -683,6 +779,7 @@
 int
 slhc_toss(struct slcompress *comp)
 {
+	DEBUGP(DSLHC, "slhc_toss(): Reset compression state...\n");
 	if ( comp == NULLSLCOMPR )
 		return 0;
 
@@ -690,55 +787,27 @@
 	return 0;
 }
 
-#else /* CONFIG_INET */
-
-int
-slhc_toss(struct slcompress *comp)
+void slhc_i_status(struct slcompress *comp)
 {
-  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss");
-  return -EINVAL;
-}
-int
-slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
-{
-  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress");
-  return -EINVAL;
-}
-int
-slhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
-	unsigned char *ocp, unsigned char **cpp, int compress_cid)
-{
-  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress");
-  return -EINVAL;
+	if (comp != NULLSLCOMPR) {
+		DEBUGP(DSLHC, "slhc_i_status(): %d Cmp, %d Uncmp, %d Bad, %d Tossed\n",
+			comp->sls_i_compressed,
+			comp->sls_i_uncompressed,
+			comp->sls_i_error,
+			comp->sls_i_tossed);
+	}
 }
 
-int
-slhc_remember(struct slcompress *comp, unsigned char *icp, int isize)
+void slhc_o_status(struct slcompress *comp)
 {
-  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember");
-  return -EINVAL;
+	if (comp != NULLSLCOMPR) {
+		DEBUGP(DSLHC, "slhc_o_status(): %d Cmp, %d Uncmp, %d AsIs, %d NotTCP %d Searches, %d Misses\n",
+			comp->sls_o_compressed,
+			comp->sls_o_uncompressed,
+			comp->sls_o_tcp,
+			comp->sls_o_nontcp,
+			comp->sls_o_searches,
+			comp->sls_o_misses);
+	}
 }
 
-void
-slhc_free(struct slcompress *comp)
-{
-  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free");
-}
-struct slcompress *
-slhc_init(int rslots, int tslots)
-{
-  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init");
-  return NULL;
-}
-
-#endif /* CONFIG_INET */
-
-/* VJ header compression */
-EXPORT_SYMBOL(slhc_init);
-EXPORT_SYMBOL(slhc_free);
-EXPORT_SYMBOL(slhc_remember);
-EXPORT_SYMBOL(slhc_compress);
-EXPORT_SYMBOL(slhc_uncompress);
-EXPORT_SYMBOL(slhc_toss);
-
-MODULE_LICENSE("Dual BSD/GPL");
diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am
index 7b145f7..2e342e0 100644
--- a/openbsc/tests/Makefile.am
+++ b/openbsc/tests/Makefile.am
@@ -11,6 +11,7 @@
 	mm_auth \
 	xid \
 	sndcp_xid \
+	slhc \
 	$(NULL)
 
 if BUILD_NAT
diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am
index cf88101..bab3f0e 100644
--- a/openbsc/tests/sgsn/Makefile.am
+++ b/openbsc/tests/sgsn/Makefile.am
@@ -58,6 +58,7 @@
 	$(top_builddir)/src/gprs/oap_messages.o \
         $(top_builddir)/src/gprs/gprs_llc_xid.o \
 	$(top_builddir)/src/gprs/gprs_sndcp_xid.o \
+        $(top_builddir)/src/gprs/slhc.o \
 	$(top_builddir)/src/libcommon/libcommon.a \
 	$(LIBOSMOABIS_LIBS) \
 	$(LIBOSMOCORE_LIBS) \
diff --git a/openbsc/tests/slhc/Makefile.am b/openbsc/tests/slhc/Makefile.am
new file mode 100644
index 0000000..32a3cc4
--- /dev/null
+++ b/openbsc/tests/slhc/Makefile.am
@@ -0,0 +1,15 @@
+AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
+AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS)
+
+EXTRA_DIST = slhc_test.ok
+
+noinst_PROGRAMS = slhc_test
+
+slhc_test_SOURCES = slhc_test.c
+
+slhc_test_LDADD = \
+	$(top_builddir)/src/gprs/slhc.o \
+	$(top_builddir)/src/libcommon/libcommon.a \
+	$(LIBOSMOCORE_LIBS)
+
+
diff --git a/openbsc/tests/slhc/slhc_test.c b/openbsc/tests/slhc/slhc_test.c
new file mode 100644
index 0000000..59a5425
--- /dev/null
+++ b/openbsc/tests/slhc/slhc_test.c
@@ -0,0 +1,298 @@
+/* Test SLHC/RFC1144 TCP/IP Header compression/decompression */
+
+/* (C) 2016 by sysmocom s.f.m.c. GmbH <info at sysmocom.de>
+ * 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 <openbsc/slhc.h>
+#include <openbsc/debug.h>
+
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/utils.h>
+
+#include <osmocom/core/application.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+/* Number of compression slots (S0-1) */
+#define SLOTS 8
+
+/* Maximum packet bytes to display */
+#define DISP_MAX_BYTES 100
+
+/* Sample packets to test with */
+#define PACKETS_LEN 6
+char *packets[] = {
+	"4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27",
+	"4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0",
+	"4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01",
+	"4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01",
+	"4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a",
+	"4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20"
+};
+
+/* Compress a packet using Van Jacobson RFC1144 header compression */
+static int compress(uint8_t *data_o, uint8_t *data_i, int len,
+		    struct slcompress *comp)
+{
+	uint8_t *comp_ptr;	/* Not used */
+	int compr_len;
+
+	/* Create a working copy of the incoming data */
+	memcpy(data_o, data_i, len);
+
+	/* Run compressor */
+	compr_len = slhc_compress(comp, data_i, len, data_o, &comp_ptr, 0);
+	return compr_len;
+}
+
+/* Expand a packet using Van Jacobson RFC1144 header compression */
+static int expand(uint8_t *data_o, uint8_t *data_i, int len,
+		  struct slcompress *comp)
+{
+	int data_decompressed_len;
+
+	/* Create a working copy of the incoming data */
+	memcpy(data_o, data_i, len);
+
+	/* Handle an uncompressed packet (learn header information */
+	if ((data_i[0] & SL_TYPE_UNCOMPRESSED_TCP) == SL_TYPE_UNCOMPRESSED_TCP) {
+		data_o[0] &= 0x4F;
+		data_decompressed_len = slhc_remember(comp, data_o, len);
+		return data_decompressed_len;
+	}
+
+	/* Uncompress compressed packets */
+	else if (data_o[0] & SL_TYPE_COMPRESSED_TCP) {
+		data_decompressed_len = slhc_uncompress(comp, data_o, len);
+		return data_decompressed_len;
+	}
+
+	/* Regular or unknown packets will not be touched */
+	return len;
+}
+
+/* Calculate IP Header checksum */
+static uint16_t calc_ip_csum(uint8_t *data, int len)
+{
+	int i;
+	uint32_t accumulator = 0;
+	uint16_t *pointer = (uint16_t *) data;
+
+	for (i = len; i > 1; i -= 2) {
+		accumulator += *pointer;
+		pointer++;
+	}
+
+	if (len % 2)
+		accumulator += *pointer;
+
+	accumulator = (accumulator & 0xffff) + ((accumulator >> 16) & 0xffff);
+	accumulator += (accumulator >> 16) & 0xffff;
+	return (~accumulator);
+}
+
+/* Calculate TCP/IP checksum */
+static uint16_t calc_tcpip_csum(const void *ctx, uint8_t *packet, int len)
+{
+	uint8_t *buf;
+	uint16_t csum;
+
+	buf = talloc_zero_size(ctx, len);
+	memset(buf, 0, len);
+	memcpy(buf, packet + 12, 8);
+	buf[9] = packet[9];
+	buf[11] = (len - 20) & 0xFF;
+	buf[10] = (len - 20) >> 8 & 0xFF;
+	memcpy(buf + 12, packet + 20, len - 20);
+	csum = calc_ip_csum(buf, len - 20 + 12);
+	talloc_free(buf);
+	return csum;
+}
+
+/* Check TCP/IP packet */
+static void check_packet(const void *ctx, uint8_t *packet, int len)
+{
+	/* Check IP header */
+	OSMO_ASSERT(len > 20);
+	OSMO_ASSERT(calc_ip_csum(packet, 20) == 0);
+
+	/* Check TCP packet */
+	if (packet[9] != 0x06)
+		return;
+	OSMO_ASSERT(len > 40);
+	OSMO_ASSERT(calc_tcpip_csum(ctx, packet, len) == 0);
+}
+
+/* Strip TCP options from TCP/IP packet */
+static int strip_tcp_options(const void *ctx, uint8_t *packet, int len)
+{
+	uint8_t doff;
+	uint16_t csum;
+
+	/* Check if the packet can be handled here */
+	if (len < 37)
+		return len;
+	if (packet[9] != 0x06)
+		return len;
+
+	/* Strip TCP/IP options from packet */
+	doff = ((packet[32] >> 4) & 0x0F) * 4;
+	memmove(packet + 40, packet + doff + 20, len - 40 - (doff - 20));
+	len = len - (doff - 20);
+
+	/* Repair data offset (TCP header length) */
+	packet[32] &= 0x0F;
+	packet[32] |= 0x50;
+
+	/* Repair checksum */
+	packet[36] = 0;
+	packet[37] = 0;
+	csum = calc_tcpip_csum(ctx, packet, len);
+	packet[36] = csum & 0xFF;
+	packet[37] = csum >> 8 & 0xFF;
+
+	/* Repair total length */
+	packet[3] = len & 0xFF;
+	packet[2] = len >> 8 & 0xFF;
+
+	/* Repair IP header checksum */
+	packet[10] = 0;
+	packet[11] = 0;
+	csum = calc_ip_csum(packet, 20);
+	packet[10] = csum & 0xFF;
+	packet[11] = csum >> 8 & 0xFF;
+	printf("csum=%04x\n", csum);
+
+	return len;
+}
+
+/* Compress / Decompress packets */
+static void test_slhc(const void *ctx)
+{
+	char packet_ascii[2048];
+	int i;
+
+	struct slcompress *comp;
+	uint8_t packet[1024];
+	int packet_len;
+	uint8_t packet_compr[1024];
+	int packet_compr_len;
+	uint8_t packet_decompr[1024];
+	int packet_decompr_len;
+
+	printf("Allocating compression state...\n");
+	comp = slhc_init(ctx, SLOTS, SLOTS);
+	OSMO_ASSERT(comp);
+
+	for(i=0;i<PACKETS_LEN;i++) {
+		/* Read input file */
+		memset(packet_ascii, 0, sizeof(packet_ascii));
+		memset(packet, 0, sizeof(packet));
+		memset(packet_compr, 0, sizeof(packet_compr));
+		memset(packet_decompr, 0, sizeof(packet_decompr));
+		strcpy(packet_ascii,packets[i]);
+
+		packet_len =
+		    osmo_hexparse(packet_ascii, packet, sizeof(packet));
+		check_packet(ctx, packet, packet_len);
+		packet_len = strip_tcp_options(ctx, packet, packet_len);
+		check_packet(ctx, packet, packet_len);
+
+		/* Run compression/decompression algorithm */
+		printf("Compressing...\n");
+		packet_compr_len =
+		    compress(packet_compr, packet, packet_len, comp);
+		printf("Decompressing...\n");
+		packet_decompr_len =
+		    expand(packet_decompr, packet_compr, packet_compr_len,
+			   comp);
+		OSMO_ASSERT(packet_decompr_len == packet_len);
+		check_packet(ctx,packet_decompr,packet_decompr_len);
+
+		/* Display results */
+		printf("Results:\n");
+		if (packet_compr_len > DISP_MAX_BYTES)
+			packet_compr_len = DISP_MAX_BYTES;
+		if (packet_len > DISP_MAX_BYTES)
+			packet_len = DISP_MAX_BYTES;
+		if (packet_decompr_len > DISP_MAX_BYTES)
+			packet_decompr_len = DISP_MAX_BYTES;
+		printf("Original Packet:    (%i bytes) %s\n", packet_len,
+		       osmo_hexdump_nospc(packet, packet_len));
+		printf("DecompressedPacket: (%i bytes) %s\n",
+		       packet_decompr_len, osmo_hexdump_nospc(packet_decompr,
+							      packet_decompr_len));
+		printf("CompressedPacket:   (%i bytes) %s\n", packet_compr_len,
+		       osmo_hexdump_nospc(packet_compr, packet_compr_len));
+		slhc_o_status(comp);
+		slhc_o_status(comp);
+
+		printf("\n");
+	}
+
+	printf("Freeing compression state...\n");
+	slhc_free(comp);
+	printf("\n");
+}
+
+static struct log_info_cat gprs_categories[] = {
+	[DSNDCP] = {
+		    .name = "DSNDCP",
+		    .description =
+		    "GPRS Sub-Network Dependent Control Protocol (SNDCP)",
+		    .enabled = 1,.loglevel = LOGL_DEBUG,
+		    },
+	[DSLHC] = {
+		   .name = "DSLHC",
+		   .description =
+		   "Van Jacobson RFC1144 TCP/IP header compression (SLHC)",
+		   .enabled = 1,.loglevel = LOGL_DEBUG,
+		   }
+};
+
+static struct log_info info = {
+	.cat = gprs_categories,
+	.num_cat = ARRAY_SIZE(gprs_categories),
+};
+
+int main(int argc, char **argv)
+{
+	void *ctx;
+
+	osmo_init_logging(&info);
+
+	ctx = talloc_named_const(NULL, 0, "slhc_ctx");
+
+	test_slhc(ctx);
+
+	printf("Done\n");
+
+	talloc_report_full(ctx, stderr);
+	OSMO_ASSERT(talloc_total_blocks(ctx) == 1);
+	return 0;
+}
+
+/* stubs */
+struct osmo_prim_hdr;
+int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
+{
+	abort();
+}
diff --git a/openbsc/tests/slhc/slhc_test.ok b/openbsc/tests/slhc/slhc_test.ok
new file mode 100644
index 0000000..636241d
--- /dev/null
+++ b/openbsc/tests/slhc/slhc_test.ok
@@ -0,0 +1,52 @@
+Allocating compression state...
+csum=b3a9
+Compressing...
+Decompressing...
+Results:
+Original Packet:    (52 bytes) 4510003446dd40004006a9b3c0a8646ec0a864640017ad8b81980100f3ac984d501800e371410000fffd18fffd20fffd23fffd27
+DecompressedPacket: (52 bytes) 4510003446dd40004006a9b3c0a8646ec0a864640017ad8b81980100f3ac984d501800e371410000fffd18fffd20fffd23fffd27
+CompressedPacket:   (52 bytes) 7510003446dd40004000a9b3c0a8646ec0a864640017ad8b81980100f3ac984d501800e371410000fffd18fffd20fffd23fffd27
+
+csum=97a9
+Compressing...
+Decompressing...
+Results:
+Original Packet:    (79 bytes) 4510004f46de40004006a997c0a8646ec0a864640017ad8b8198010cf3ac984d501800e3cda40000fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0
+DecompressedPacket: (79 bytes) 4510004f46de40004006a997c0a8646ec0a864640017ad8b8198010cf3ac984d501800e3cda40000fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0
+CompressedPacket:   (43 bytes) df00cda4fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0
+
+csum=baa9
+Compressing...
+Decompressing...
+Results:
+Original Packet:    (43 bytes) 4510002b46df40004006a9bac0a8646ec0a864640017ad8b81980133f3ac989f501800e3a70a0000fffd01
+DecompressedPacket: (43 bytes) 4510002b46df40004006a9bac0a8646ec0a864640017ad8b81980133f3ac989f501800e3a70a0000fffd01
+CompressedPacket:   (9 bytes) dc00a70a5227fffd01
+
+csum=b9a9
+Compressing...
+Decompressing...
+Results:
+Original Packet:    (43 bytes) 4510002b46e040004006a9b9c0a8646ec0a864640017ad8b81980136f3ac98a2501800e3a7060000fffb01
+DecompressedPacket: (43 bytes) 4510002b46e040004006a9b9c0a8646ec0a864640017ad8b81980136f3ac98a2501800e3a7060000fffb01
+CompressedPacket:   (7 bytes) db00a706fffb01
+
+csum=7ba9
+Compressing...
+Decompressing...
+Results:
+Original Packet:    (100 bytes) 4510006846e140004006a97bc0a8646ec0a864640017ad8b81980139f3ac98a5501800e3c2d000000d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d
+DecompressedPacket: (100 bytes) 4510006846e140004006a97bc0a8646ec0a864640017ad8b81980139f3ac98a5501800e3c2d000000d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d
+CompressedPacket:   (68 bytes) db00c2d00d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a
+
+csum=aca9
+Compressing...
+Decompressing...
+Results:
+Original Packet:    (54 bytes) 4510003646e240004006a9acc0a8646ec0a864640017ad8b81980179f3ac98a5501800e321fb0000706f6c6c7578206c6f67696e3a20
+DecompressedPacket: (54 bytes) 4510003646e240004006a9acc0a8646ec0a864640017ad8b81980179f3ac98a5501800e321fb0000706f6c6c7578206c6f67696e3a20
+CompressedPacket:   (18 bytes) df0021fb706f6c6c7578206c6f67696e3a20
+
+Freeing compression state...
+
+Done
diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at
index 85a81d6..5f37b8e 100644
--- a/openbsc/tests/testsuite.at
+++ b/openbsc/tests/testsuite.at
@@ -136,3 +136,8 @@
 AT_CHECK([$abs_top_builddir/tests/sndcp_xid/sndcp_xid_test], [], [expout], [ignore])
 AT_CLEANUP
 
+AT_SETUP([slhc])
+AT_KEYWORDS([slhc])
+cat $abs_srcdir/slhc/slhc_test.ok > expout
+AT_CHECK([$abs_top_builddir/tests/slhc/slhc_test], [], [expout], [ignore])
+AT_CLEANUP

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

Gerrit-MessageType: merged
Gerrit-Change-Id: I7a638e88a43b3eb9d006751a03ef2570e36613f0
Gerrit-PatchSet: 20
Gerrit-Project: openbsc
Gerrit-Branch: master
Gerrit-Owner: dexter <pmaier at sysmocom.de>
Gerrit-Reviewer: Harald Welte <laforge at gnumonks.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: Neels Hofmeyr <nhofmeyr at sysmocom.de>



More information about the gerrit-log mailing list