aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--openbsc/.gitignore1
-rw-r--r--openbsc/configure.ac1
-rw-r--r--openbsc/include/openbsc/mncc.h1
-rw-r--r--openbsc/include/openbsc/trau_mux.h10
-rw-r--r--openbsc/src/libmsc/gsm_04_08.c1
-rw-r--r--openbsc/src/libtrau/trau_mux.c307
-rw-r--r--openbsc/tests/Makefile.am2
-rw-r--r--openbsc/tests/testsuite.at6
-rw-r--r--openbsc/tests/trau/Makefile.am17
-rw-r--r--openbsc/tests/trau/trau_test.c82
-rw-r--r--openbsc/tests/trau/trau_test.ok10
11 files changed, 379 insertions, 59 deletions
diff --git a/openbsc/.gitignore b/openbsc/.gitignore
index e977f8494..c57ae4b9c 100644
--- a/openbsc/.gitignore
+++ b/openbsc/.gitignore
@@ -66,6 +66,7 @@ tests/abis/abis_test
tests/si/si_test
tests/smpp/smpp_test
tests/bsc/bsc_test
+tests/trau/trau_test
tests/atconfig
tests/atlocal
diff --git a/openbsc/configure.ac b/openbsc/configure.ac
index 081e416d7..fe9956976 100644
--- a/openbsc/configure.ac
+++ b/openbsc/configure.ac
@@ -169,6 +169,7 @@ AC_OUTPUT(
tests/si/Makefile
tests/abis/Makefile
tests/smpp/Makefile
+ tests/trau/Makefile
doc/Makefile
doc/examples/Makefile
Makefile)
diff --git a/openbsc/include/openbsc/mncc.h b/openbsc/include/openbsc/mncc.h
index 4a99bb11b..ffc247b7c 100644
--- a/openbsc/include/openbsc/mncc.h
+++ b/openbsc/include/openbsc/mncc.h
@@ -95,6 +95,7 @@ struct gsm_call {
#define GSM_TCHF_FRAME 0x0300
#define GSM_TCHF_FRAME_EFR 0x0301
+#define GSM_TCHF_BAD_FRAME 0x03ff
#define MNCC_SOCKET_HELLO 0x0400
diff --git a/openbsc/include/openbsc/trau_mux.h b/openbsc/include/openbsc/trau_mux.h
index 2c01b06db..3de50f772 100644
--- a/openbsc/include/openbsc/trau_mux.h
+++ b/openbsc/include/openbsc/trau_mux.h
@@ -53,3 +53,13 @@ int trau_send_frame(struct gsm_lchan *lchan, struct gsm_data_frame *frame);
/* callback invoked if we receive TRAU frames */
int subch_cb(struct subch_demux *dmx, int ch, uint8_t *data, int len, void *_priv);
+
+/* TRAU frame transcoding */
+struct msgb *trau_decode_fr(uint32_t callref,
+ const struct decoded_trau_frame *tf);
+struct msgb *trau_decode_efr(uint32_t callref,
+ const struct decoded_trau_frame *tf);
+void trau_encode_fr(struct decoded_trau_frame *tf,
+ const unsigned char *data);
+void trau_encode_efr(struct decoded_trau_frame *tf,
+ const unsigned char *data);
diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c
index 3cfc455df..63603934b 100644
--- a/openbsc/src/libmsc/gsm_04_08.c
+++ b/openbsc/src/libmsc/gsm_04_08.c
@@ -2876,6 +2876,7 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg)
case MNCC_FRAME_RECV:
return tch_recv_mncc(net, data->callref, 1);
case GSM_TCHF_FRAME:
+ case GSM_TCHF_FRAME_EFR:
/* Find callref */
trans = trans_find_by_callref(net, data->callref);
if (!trans) {
diff --git a/openbsc/src/libtrau/trau_mux.c b/openbsc/src/libtrau/trau_mux.c
index 9272ac04f..c9d77cf78 100644
--- a/openbsc/src/libtrau/trau_mux.c
+++ b/openbsc/src/libtrau/trau_mux.c
@@ -30,6 +30,7 @@
#include <openbsc/debug.h>
#include <osmocom/core/talloc.h>
#include <openbsc/trau_upqueue.h>
+#include <osmocom/core/crcgen.h>
/* this corresponds to the bit-lengths of the individual codec
* parameters as indicated in Table 1.1 of TS 06.10 */
@@ -46,6 +47,53 @@ static const uint8_t gsm_fr_map[] = {
3, 3, 3, 3
};
+
+/*
+ * EFR TRAU parity
+ *
+ * g(x) = x^3 + x^1 + 1
+ */
+static const struct osmo_crc8gen_code gsm0860_efr_crc3 = {
+ .bits = 3,
+ .poly = 0x3,
+ .init = 0x0,
+ .remainder = 0x7,
+};
+
+/* EFR parity bits */
+static inline void efr_parity_bits_1(ubit_t *check_bits, const ubit_t *d_bits)
+{
+ memcpy(check_bits + 0 , d_bits + 0, 22);
+ memcpy(check_bits + 22 , d_bits + 24, 3);
+ check_bits[25] = d_bits[28];
+}
+
+static inline void efr_parity_bits_2(ubit_t *check_bits, const ubit_t *d_bits)
+{
+ memcpy(check_bits + 0 , d_bits + 42, 10);
+ memcpy(check_bits + 10 , d_bits + 90, 2);
+}
+
+static inline void efr_parity_bits_3(ubit_t *check_bits, const ubit_t *d_bits)
+{
+ memcpy(check_bits + 0 , d_bits + 98, 5);
+ check_bits[5] = d_bits[104];
+ memcpy(check_bits + 6 , d_bits + 143, 2);
+}
+
+static inline void efr_parity_bits_4(ubit_t *check_bits, const ubit_t *d_bits)
+{
+ memcpy(check_bits + 0 , d_bits + 151, 10);
+ memcpy(check_bits + 10 , d_bits + 199, 2);
+}
+
+static inline void efr_parity_bits_5(ubit_t *check_bits, const ubit_t *d_bits)
+{
+ memcpy(check_bits + 0 , d_bits + 207, 5);
+ check_bits[5] = d_bits[213];
+ memcpy(check_bits + 6 , d_bits + 252, 2);
+}
+
struct map_entry {
struct llist_head list;
struct gsm_e1_subslot src, dst;
@@ -158,7 +206,117 @@ lookup_trau_upqueue(const struct gsm_e1_subslot *src)
return NULL;
}
-static const uint8_t c_bits_check[] = { 0, 0, 0, 1, 0 };
+static const uint8_t c_bits_check_fr[] = { 0, 0, 0, 1, 0 };
+static const uint8_t c_bits_check_efr[] = { 1, 1, 0, 1, 0 };
+
+struct msgb *trau_decode_fr(uint32_t callref,
+ const struct decoded_trau_frame *tf)
+{
+ struct msgb *msg;
+ struct gsm_data_frame *frame;
+ unsigned char *data;
+ int i, j, k, l, o;
+
+ msg = msgb_alloc(sizeof(struct gsm_data_frame) + 33,
+ "GSM-DATA");
+ if (!msg)
+ return NULL;
+
+ frame = (struct gsm_data_frame *)msg->data;
+ memset(frame, 0, sizeof(struct gsm_data_frame));
+ data = frame->data;
+ data[0] = 0xd << 4;
+ /* reassemble d-bits */
+ i = 0; /* counts bits */
+ j = 4; /* counts output bits */
+ k = gsm_fr_map[0]-1; /* current number bit in element */
+ l = 0; /* counts element bits */
+ o = 0; /* offset input bits */
+ while (i < 260) {
+ data[j/8] |= (tf->d_bits[k+o] << (7-(j%8)));
+ if (--k < 0) {
+ o += gsm_fr_map[l];
+ k = gsm_fr_map[++l]-1;
+ }
+ i++;
+ j++;
+ }
+ frame->msg_type = GSM_TCHF_FRAME;
+ frame->callref = callref;
+ msgb_put(msg, sizeof(struct gsm_data_frame) + 33);
+
+ return msg;
+}
+
+struct msgb *trau_decode_efr(uint32_t callref,
+ const struct decoded_trau_frame *tf)
+{
+ struct msgb *msg;
+ struct gsm_data_frame *frame;
+ unsigned char *data;
+ int i, j, rc;
+ ubit_t check_bits[26];
+
+ msg = msgb_alloc(sizeof(struct gsm_data_frame) + 31,
+ "GSM-DATA");
+ if (!msg)
+ return NULL;
+
+ frame = (struct gsm_data_frame *)msg->data;
+ memset(frame, 0, sizeof(struct gsm_data_frame));
+ frame->msg_type = GSM_TCHF_FRAME_EFR;
+ frame->callref = callref;
+ msgb_put(msg, sizeof(struct gsm_data_frame) + 31);
+
+ if (tf->c_bits[11]) /* BFI */
+ goto bad_frame;
+
+ data = frame->data;
+ data[0] = 0xc << 4;
+ /* reassemble d-bits */
+ for (i = 1, j = 4; i < 39; i++, j++)
+ data[j/8] |= (tf->d_bits[i] << (7-(j%8)));
+ efr_parity_bits_1(check_bits, tf->d_bits);
+ rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 26,
+ tf->d_bits + 39);
+ if (rc)
+ goto bad_frame;
+ for (i = 42, j = 42; i < 95; i++, j++)
+ data[j/8] |= (tf->d_bits[i] << (7-(j%8)));
+ efr_parity_bits_2(check_bits, tf->d_bits);
+ rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 12,
+ tf->d_bits + 95);
+ if (rc)
+ goto bad_frame;
+ for (i = 98, j = 95; i < 148; i++, j++)
+ data[j/8] |= (tf->d_bits[i] << (7-(j%8)));
+ efr_parity_bits_3(check_bits, tf->d_bits);
+ rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 8,
+ tf->d_bits + 148);
+ if (rc)
+ goto bad_frame;
+ for (i = 151, j = 145; i < 204; i++, j++)
+ data[j/8] |= (tf->d_bits[i] << (7-(j%8)));
+ efr_parity_bits_4(check_bits, tf->d_bits);
+ rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 12,
+ tf->d_bits + 204);
+ if (rc)
+ goto bad_frame;
+ for (i = 207, j = 198; i < 257; i++, j++)
+ data[j/8] |= (tf->d_bits[i] << (7-(j%8)));
+ efr_parity_bits_5(check_bits, tf->d_bits);
+ rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 8,
+ tf->d_bits + 257);
+ if (rc)
+ goto bad_frame;
+
+ return msg;
+
+bad_frame:
+ frame->msg_type = GSM_TCHF_BAD_FRAME;
+
+ return msg;
+}
/* we get called by subchan_demux */
int trau_mux_input(struct gsm_e1_subslot *src_e1_ss,
@@ -177,45 +335,25 @@ int trau_mux_input(struct gsm_e1_subslot *src_e1_ss,
return rc;
if (!dst_e1_ss) {
- struct msgb *msg;
- struct gsm_data_frame *frame;
- unsigned char *data;
- int i, j, k, l, o;
+ struct msgb *msg = NULL;
/* frame shall be sent to upqueue */
if (!(ue = lookup_trau_upqueue(src_e1_ss)))
return -EINVAL;
if (!ue->callref)
return -EINVAL;
- if (memcmp(tf.c_bits, c_bits_check, sizeof(c_bits_check)))
+ if (!memcmp(tf.c_bits, c_bits_check_fr, 5))
+ msg = trau_decode_fr(ue->callref, &tf);
+ else if (!memcmp(tf.c_bits, c_bits_check_efr, 5))
+ msg = trau_decode_efr(ue->callref, &tf);
+ else {
DEBUGPC(DLMUX, "illegal trau (C1-C5) %s\n",
- osmo_hexdump(tf.c_bits, sizeof(c_bits_check)));
- msg = msgb_alloc(sizeof(struct gsm_data_frame) + 33,
- "GSM-DATA");
+ osmo_hexdump(tf.c_bits, 5));
+ DEBUGPC(DLMUX, "test trau (C1-C5) %s\n",
+ osmo_hexdump(c_bits_check_efr, 5));
+ return -EINVAL;
+ }
if (!msg)
return -ENOMEM;
-
- frame = (struct gsm_data_frame *)msg->data;
- memset(frame, 0, sizeof(struct gsm_data_frame));
- data = frame->data;
- data[0] = 0xd << 4;
- /* reassemble d-bits */
- i = 0; /* counts bits */
- j = 4; /* counts output bits */
- k = gsm_fr_map[0]-1; /* current number bit in element */
- l = 0; /* counts element bits */
- o = 0; /* offset input bits */
- while (i < 260) {
- data[j/8] |= (tf.d_bits[k+o] << (7-(j%8)));
- if (--k < 0) {
- o += gsm_fr_map[l];
- k = gsm_fr_map[++l]-1;
- }
- i++;
- j++;
- }
- frame->msg_type = GSM_TCHF_FRAME;
- frame->callref = ue->callref;
- msgb_put(msg, sizeof(struct gsm_data_frame) + 33);
trau_tx_to_mncc(ue->net, msg);
return 0;
@@ -275,13 +413,86 @@ int trau_recv_lchan(struct gsm_lchan *lchan, uint32_t callref)
return 0;
}
+void trau_encode_fr(struct decoded_trau_frame *tf,
+ const unsigned char *data)
+{
+ int i, j, k, l, o;
+
+ /* set c-bits and t-bits */
+ tf->c_bits[0] = 1;
+ tf->c_bits[1] = 1;
+ tf->c_bits[2] = 1;
+ tf->c_bits[3] = 0;
+ tf->c_bits[4] = 0;
+ memset(&tf->c_bits[5], 0, 6);
+ memset(&tf->c_bits[11], 1, 10);
+ memset(&tf->t_bits[0], 1, 4);
+ /* reassemble d-bits */
+ i = 0; /* counts bits */
+ j = 4; /* counts input bits */
+ k = gsm_fr_map[0]-1; /* current number bit in element */
+ l = 0; /* counts element bits */
+ o = 0; /* offset output bits */
+ while (i < 260) {
+ tf->d_bits[k+o] = (data[j/8] >> (7-(j%8))) & 1;
+ if (--k < 0) {
+ o += gsm_fr_map[l];
+ k = gsm_fr_map[++l]-1;
+ }
+ i++;
+ j++;
+ }
+}
+
+void trau_encode_efr(struct decoded_trau_frame *tf,
+ const unsigned char *data)
+{
+ int i, j;
+ ubit_t check_bits[26];
+
+ /* set c-bits and t-bits */
+ tf->c_bits[0] = 1;
+ tf->c_bits[1] = 1;
+ tf->c_bits[2] = 0;
+ tf->c_bits[3] = 1;
+ tf->c_bits[4] = 0;
+ memset(&tf->c_bits[5], 0, 6);
+ memset(&tf->c_bits[11], 1, 10);
+ memset(&tf->t_bits[0], 1, 4);
+ /* reassemble d-bits */
+ tf->d_bits[0] = 1;
+ for (i = 1, j = 4; i < 39; i++, j++)
+ tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1;
+ efr_parity_bits_1(check_bits, tf->d_bits);
+ osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 26,
+ tf->d_bits + 39);
+ for (i = 42, j = 42; i < 95; i++, j++)
+ tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1;
+ efr_parity_bits_2(check_bits, tf->d_bits);
+ osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 12,
+ tf->d_bits + 95);
+ for (i = 98, j = 95; i < 148; i++, j++)
+ tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1;
+ efr_parity_bits_3(check_bits, tf->d_bits);
+ osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 8,
+ tf->d_bits + 148);
+ for (i = 151, j = 145; i < 204; i++, j++)
+ tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1;
+ efr_parity_bits_4(check_bits, tf->d_bits);
+ osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 12,
+ tf->d_bits + 204);
+ for (i = 207, j = 198; i < 257; i++, j++)
+ tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1;
+ efr_parity_bits_5(check_bits, tf->d_bits);
+ osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 8,
+ tf->d_bits + 257);
+}
+
int trau_send_frame(struct gsm_lchan *lchan, struct gsm_data_frame *frame)
{
uint8_t trau_bits_out[TRAU_FRAME_BITS];
struct gsm_e1_subslot *dst_e1_ss = &lchan->ts->e1_link;
struct subch_mux *mx;
- int i, j, k, l, o;
- unsigned char *data = frame->data;
struct decoded_trau_frame tf;
mx = e1inp_get_mux(dst_e1_ss->e1_nr, dst_e1_ss->e1_ts);
@@ -290,30 +501,10 @@ int trau_send_frame(struct gsm_lchan *lchan, struct gsm_data_frame *frame)
switch (frame->msg_type) {
case GSM_TCHF_FRAME:
- /* set c-bits and t-bits */
- tf.c_bits[0] = 1;
- tf.c_bits[1] = 1;
- tf.c_bits[2] = 1;
- tf.c_bits[3] = 0;
- tf.c_bits[4] = 0;
- memset(&tf.c_bits[5], 0, 6);
- memset(&tf.c_bits[11], 1, 10);
- memset(&tf.t_bits[0], 1, 4);
- /* reassemble d-bits */
- i = 0; /* counts bits */
- j = 4; /* counts input bits */
- k = gsm_fr_map[0]-1; /* current number bit in element */
- l = 0; /* counts element bits */
- o = 0; /* offset output bits */
- while (i < 260) {
- tf.d_bits[k+o] = (data[j/8] >> (7-(j%8))) & 1;
- if (--k < 0) {
- o += gsm_fr_map[l];
- k = gsm_fr_map[++l]-1;
- }
- i++;
- j++;
- }
+ trau_encode_fr(&tf, frame->data);
+ break;
+ case GSM_TCHF_FRAME_EFR:
+ trau_encode_efr(&tf, frame->data);
break;
default:
DEBUGPC(DLMUX, "unsupported message type %d\n",
diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am
index 7f51bfa13..d4bb954a6 100644
--- a/openbsc/tests/Makefile.am
+++ b/openbsc/tests/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = gsm0408 db channel mgcp gprs si abis gbproxy
+SUBDIRS = gsm0408 db channel mgcp gprs si abis gbproxy trau
if BUILD_NAT
SUBDIRS += bsc-nat bsc-nat-trie
diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at
index 76110f5d9..652cfe96c 100644
--- a/openbsc/tests/testsuite.at
+++ b/openbsc/tests/testsuite.at
@@ -81,3 +81,9 @@ AT_KEYWORDS([gbproxy])
cat $abs_srcdir/gbproxy/gbproxy_test.ok > expout
AT_CHECK([$abs_top_builddir/tests/gbproxy/gbproxy_test], [], [expout], [ignore])
AT_CLEANUP
+
+AT_SETUP([trau])
+AT_KEYWORDS([trau])
+cat $abs_srcdir/trau/trau_test.ok > expout
+AT_CHECK([$abs_top_builddir/tests/trau/trau_test], [], [expout], [ignore])
+AT_CLEANUP
diff --git a/openbsc/tests/trau/Makefile.am b/openbsc/tests/trau/Makefile.am
new file mode 100644
index 000000000..d4aa1c327
--- /dev/null
+++ b/openbsc/tests/trau/Makefile.am
@@ -0,0 +1,17 @@
+AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
+AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(LIBSMPP34_CFLAGS) $(COVERAGE_CFLAGS)
+AM_LDFLAGS = $(COVERAGE_LDFLAGS)
+
+EXTRA_DIST = trau_test.ok
+
+noinst_PROGRAMS = trau_test
+
+trau_test_SOURCES = trau_test.c
+trau_test_LDADD = $(top_builddir)/src/libbsc/libbsc.a \
+ $(top_builddir)/src/libmsc/libmsc.a \
+ $(top_builddir)/src/libbsc/libbsc.a \
+ $(top_builddir)/src/libtrau/libtrau.a \
+ $(top_builddir)/src/libcommon/libcommon.a \
+ $(LIBOSMOCORE_LIBS) $(LIBOSMOABIS_LIBS) \
+ $(LIBOSMOGSM_LIBS) $(LIBSMPP34_LIBS) $(LIBOSMOVTY_LIBS) -ldl -ldbi
+
diff --git a/openbsc/tests/trau/trau_test.c b/openbsc/tests/trau/trau_test.c
new file mode 100644
index 000000000..f8a48dbd8
--- /dev/null
+++ b/openbsc/tests/trau/trau_test.c
@@ -0,0 +1,82 @@
+/* (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
+ * All Rights Reserved
+ *
+ * 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 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 <osmocom/abis/trau_frame.h>
+#include <openbsc/trau_mux.h>
+#include <osmocom/core/msgb.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+void test_trau_fr_efr(unsigned char *data)
+{
+ struct decoded_trau_frame tf;
+ struct msgb *msg;
+ struct gsm_data_frame *frame;
+
+ printf("Testing TRAU FR transcoding.\n");
+ data[0] = 0xd0;
+ trau_encode_fr(&tf, data);
+ tf.c_bits[11] = 0; /* clear BFI */
+ msg = trau_decode_fr(1, &tf);
+ OSMO_ASSERT(msg != NULL);
+ frame = (struct gsm_data_frame *)msg->data;
+ OSMO_ASSERT(frame->msg_type == GSM_TCHF_FRAME);
+ OSMO_ASSERT(!memcmp(frame->data, data, 33));
+ msgb_free(msg);
+
+ printf("Testing TRAU EFR transcoding.\n");
+ data[0] = 0xc0;
+ trau_encode_efr(&tf, data);
+ OSMO_ASSERT(tf.d_bits[0] == 1); /* spare bit must be 1 */
+ tf.c_bits[11] = 0; /* clear BFI */
+ msg = trau_decode_efr(1, &tf);
+ OSMO_ASSERT(msg != NULL);
+ frame = (struct gsm_data_frame *)msg->data;
+ OSMO_ASSERT(frame->msg_type == GSM_TCHF_FRAME_EFR);
+ OSMO_ASSERT(!memcmp(frame->data, data, 31));
+
+ printf("Testing TRAU EFR decoding with CRC error.\n");
+ tf.d_bits[0] = 0; /* spare bit must be included */
+ msg = trau_decode_efr(1, &tf);
+ OSMO_ASSERT(msg != NULL);
+ frame = (struct gsm_data_frame *)msg->data;
+ OSMO_ASSERT(frame->msg_type == GSM_TCHF_BAD_FRAME);
+ msgb_free(msg);
+}
+
+int main()
+{
+ unsigned char data[33];
+ int i;
+
+ memset(data, 0x00, sizeof(data));
+ test_trau_fr_efr(data);
+ memset(data, 0xff, sizeof(data));
+ test_trau_fr_efr(data);
+ srandom(42);
+ for (i = 0; i < sizeof(data); i++)
+ data[i] = random();
+ test_trau_fr_efr(data);
+ printf("Done\n");
+ return 0;
+}
+
+/* stubs */
+void vty_out() {}
diff --git a/openbsc/tests/trau/trau_test.ok b/openbsc/tests/trau/trau_test.ok
new file mode 100644
index 000000000..ef7123073
--- /dev/null
+++ b/openbsc/tests/trau/trau_test.ok
@@ -0,0 +1,10 @@
+Testing TRAU FR transcoding.
+Testing TRAU EFR transcoding.
+Testing TRAU EFR decoding with CRC error.
+Testing TRAU FR transcoding.
+Testing TRAU EFR transcoding.
+Testing TRAU EFR decoding with CRC error.
+Testing TRAU FR transcoding.
+Testing TRAU EFR transcoding.
+Testing TRAU EFR decoding with CRC error.
+Done