aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilipp <pmaier@sysmocom.de>2016-08-26 16:58:41 +0200
committerHarald Welte <laforge@gnumonks.org>2016-09-24 03:17:58 +0000
commit2c7f83762ab28ef4051d379e295a824e83577d7f (patch)
treed46bb7f13dfc9a5fe86bc35eda7adecd990b37ce
parentb3e116c74d487fa7bf25e5aaa71130eef896153e (diff)
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
-rw-r--r--openbsc/.gitignore1
-rw-r--r--openbsc/configure.ac1
-rw-r--r--openbsc/include/openbsc/Makefile.am1
-rw-r--r--openbsc/include/openbsc/debug.h1
-rw-r--r--openbsc/include/openbsc/slhc.h (renamed from openbsc/include/openbsc/slhc_vj.h)6
-rw-r--r--openbsc/src/gprs/Makefile.am1
-rw-r--r--openbsc/src/gprs/sgsn_main.c5
-rw-r--r--openbsc/src/gprs/slhc.c245
-rw-r--r--openbsc/tests/Makefile.am1
-rw-r--r--openbsc/tests/sgsn/Makefile.am1
-rw-r--r--openbsc/tests/slhc/Makefile.am15
-rw-r--r--openbsc/tests/slhc/slhc_test.c298
-rw-r--r--openbsc/tests/slhc/slhc_test.ok52
-rw-r--r--openbsc/tests/testsuite.at5
14 files changed, 544 insertions, 89 deletions
diff --git a/openbsc/.gitignore b/openbsc/.gitignore
index 8ce3b7033..e75b9eb98 100644
--- a/openbsc/.gitignore
+++ b/openbsc/.gitignore
@@ -83,6 +83,7 @@ tests/gtphub/gtphub_test
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 9dc2f8d97..cebabdc58 100644
--- a/openbsc/configure.ac
+++ b/openbsc/configure.ac
@@ -232,6 +232,7 @@ AC_OUTPUT(
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 a91322fa6..12e1a664e 100644
--- a/openbsc/include/openbsc/Makefile.am
+++ b/openbsc/include/openbsc/Makefile.am
@@ -65,6 +65,7 @@ noinst_HEADERS = \
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 43ebb19a0..90ddca5a2 100644
--- a/openbsc/include/openbsc/debug.h
+++ b/openbsc/include/openbsc/debug.h
@@ -29,6 +29,7 @@ enum {
DBSSGP,
DLLC,
DSNDCP,
+ DSLHC,
DNAT,
DCTRL,
DSMPP,
diff --git a/openbsc/include/openbsc/slhc_vj.h b/openbsc/include/openbsc/slhc.h
index 8716d5942..cd5a47cf4 100644
--- a/openbsc/include/openbsc/slhc_vj.h
+++ b/openbsc/include/openbsc/slhc.h
@@ -171,7 +171,8 @@ struct slcompress {
#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_uncompress(struct slcompress *comp, unsigned char *icp, int isize);
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 3b5839997..06c12d7d9 100644
--- a/openbsc/src/gprs/Makefile.am
+++ b/openbsc/src/gprs/Makefile.am
@@ -87,6 +87,7 @@ osmo_sgsn_SOURCES = \
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 7d533c060..9f3260d55 100644
--- a/openbsc/src/gprs/sgsn_main.c
+++ b/openbsc/src/gprs/sgsn_main.c
@@ -294,6 +294,11 @@ static struct log_info_cat gprs_categories[] = {
.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 27ed25252..cbdf8dbd8 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>
-
-#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>
+#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>
+
+#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 @@ slhc_init(int rslots, int tslots)
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 @@ slhc_init(int rslots, int tslots)
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 @@ out_fail:
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 @@ encode(unsigned char *cp, unsigned short n)
} else {
*cp++ = n;
}
+
+ DEBUGP(DSLHC, "encode(): n=%04x\n",n);
return cp;
}
@@ -256,6 +276,7 @@ slhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
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 @@ slhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
! (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 @@ slhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
* 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 @@ slhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
* 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 @@ found:
*/
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 @@ found:
|| 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 @@ found:
*/
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 @@ found:
* 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 @@ found:
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 @@ found:
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 @@ found:
}
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 @@ found:
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 @@ found:
*(__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 @@ found:
* 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 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
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 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
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 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
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 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
return len;
bad:
+ DEBUGP(DSLHC, "slhc_uncompress(): bad packet detected!\n");
comp->sls_i_error++;
return slhc_toss( comp );
}
@@ -641,6 +733,7 @@ slhc_remember(struct slcompress *comp, unsigned char *icp, int isize)
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 @@ slhc_remember(struct slcompress *comp, unsigned char *icp, int isize)
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 @@ slhc_remember(struct slcompress *comp, unsigned char *icp, int isize)
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 @@ slhc_remember(struct slcompress *comp, unsigned char *icp, int isize)
int
slhc_toss(struct slcompress *comp)
{
+ DEBUGP(DSLHC, "slhc_toss(): Reset compression state...\n");
if ( comp == NULLSLCOMPR )
return 0;
@@ -690,55 +787,27 @@ slhc_toss(struct slcompress *comp)
return 0;
}
-#else /* CONFIG_INET */
-
-int
-slhc_toss(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)
+void slhc_i_status(struct slcompress *comp)
{
- 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;
-}
-
-int
-slhc_remember(struct slcompress *comp, unsigned char *icp, int isize)
-{
- printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember");
- 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);
+ }
}
-void
-slhc_free(struct slcompress *comp)
+void slhc_o_status(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;
+ 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);
+ }
}
-#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 7b145f789..2e342e0aa 100644
--- a/openbsc/tests/Makefile.am
+++ b/openbsc/tests/Makefile.am
@@ -11,6 +11,7 @@ SUBDIRS = \
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 cf8810160..bab3f0ef1 100644
--- a/openbsc/tests/sgsn/Makefile.am
+++ b/openbsc/tests/sgsn/Makefile.am
@@ -58,6 +58,7 @@ sgsn_test_LDADD = \
$(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 000000000..32a3cc447
--- /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 000000000..59a54259d
--- /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@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 000000000..636241dba
--- /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 85a81d6d5..5f37b8e22 100644
--- a/openbsc/tests/testsuite.at
+++ b/openbsc/tests/testsuite.at
@@ -136,3 +136,8 @@ cat $abs_srcdir/sndcp_xid/sndcp_xid_test.ok > expout
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