summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/Makefile.am47
-rw-r--r--tests/a5/Makefile.am6
-rw-r--r--tests/a5/a5_test.c98
-rw-r--r--tests/a5/a5_test.ok6
-rw-r--r--tests/auth/Makefile.am8
-rw-r--r--tests/auth/milenage_test.c98
-rw-r--r--tests/auth/milenage_test.ok10
-rw-r--r--tests/bits/Makefile.am7
-rw-r--r--tests/bits/bitrev_test.c36
-rw-r--r--tests/bits/bitrev_test.ok24
-rw-r--r--tests/conv/Makefile.am6
-rw-r--r--tests/conv/conv_test.c486
-rw-r--r--tests/conv/conv_test.ok55
-rw-r--r--tests/gsm0808/Makefile.am6
-rw-r--r--tests/gsm0808/gsm0808_test.c269
-rw-r--r--tests/gsm0808/gsm0808_test.ok15
-rw-r--r--tests/lapd/Makefile.am9
-rw-r--r--tests/lapd/lapd_test.c319
-rw-r--r--tests/lapd/lapd_test.ok20
-rw-r--r--tests/msgfile/Makefile.am6
-rw-r--r--tests/msgfile/msgconfig.cfg2
-rw-r--r--tests/msgfile/msgfile_test.c50
-rw-r--r--tests/msgfile/msgfile_test.ok1
-rw-r--r--tests/sms/Makefile.am6
-rw-r--r--tests/sms/sms_test.c319
-rw-r--r--tests/sms/sms_test.ok2
-rw-r--r--tests/smscb/Makefile.am6
-rw-r--r--tests/smscb/smscb_test.c41
-rw-r--r--tests/smscb/smscb_test.ok4
-rw-r--r--tests/testsuite.at73
-rw-r--r--tests/timer/Makefile.am7
-rw-r--r--tests/timer/timer_test.c191
-rw-r--r--tests/timer/timer_test.ok2
-rw-r--r--tests/ussd/Makefile.am6
-rw-r--r--tests/ussd/ussd_test.c97
-rw-r--r--tests/ussd/ussd_test.ok53
36 files changed, 2391 insertions, 0 deletions
diff --git a/tests/Makefile.am b/tests/Makefile.am
new file mode 100644
index 00000000..eff1ac44
--- /dev/null
+++ b/tests/Makefile.am
@@ -0,0 +1,47 @@
+if ENABLE_TESTS
+SUBDIRS = timer sms ussd smscb bits a5 conv auth lapd gsm0808
+if ENABLE_MSGFILE
+SUBDIRS += msgfile
+endif
+
+
+# The `:;' works around a Bash 3.2 bug when the output is not writeable.
+$(srcdir)/package.m4: $(top_srcdir)/configure.ac
+ :;{ \
+ echo '# Signature of the current package.' && \
+ echo 'm4_define([AT_PACKAGE_NAME],' && \
+ echo ' [$(PACKAGE_NAME)])' && \
+ echo 'm4_define([AT_PACKAGE_TARNAME],' && \
+ echo ' [$(PACKAGE_TARNAME)])' && \
+ echo 'm4_define([AT_PACKAGE_VERSION],' && \
+ echo ' [$(PACKAGE_VERSION)])' && \
+ echo 'm4_define([AT_PACKAGE_STRING],' && \
+ echo ' [$(PACKAGE_STRING)])' && \
+ echo 'm4_define([AT_PACKAGE_BUGREPORT],' && \
+ echo ' [$(PACKAGE_BUGREPORT)])'; \
+ echo 'm4_define([AT_PACKAGE_URL],' && \
+ echo ' [$(PACKAGE_URL)])'; \
+ } >'$(srcdir)/package.m4'
+
+EXTRA_DIST = testsuite.at $(srcdir)/package.m4 $(TESTSUITE)
+TESTSUITE = $(srcdir)/testsuite
+
+check-local: atconfig $(TESTSUITE)
+ $(SHELL) '$(TESTSUITE)' $(TESTSUITEFLAGS)
+
+installcheck-local: atconfig $(TESTSUITE)
+ $(SHELL) '$(TESTSUITE)' AUTOTEST_PATH='$(bindir)' \
+ $(TESTSUITEFLAGS)
+
+clean-local:
+ test ! -f '$(TESTSUITE)' || \
+ $(SHELL) '$(TESTSUITE)' --clean
+ $(RM) -f atconfig
+
+AUTOM4TE = $(SHELL) $(top_srcdir)/missing --run autom4te
+AUTOTEST = $(AUTOM4TE) --language=autotest
+$(TESTSUITE): $(srcdir)/testsuite.at $(srcdir)/package.m4
+ $(AUTOTEST) -I '$(srcdir)' -o $@.tmp $@.at
+ mv $@.tmp $@
+
+endif
diff --git a/tests/a5/Makefile.am b/tests/a5/Makefile.am
new file mode 100644
index 00000000..3c6e6ba4
--- /dev/null
+++ b/tests/a5/Makefile.am
@@ -0,0 +1,6 @@
+INCLUDES = $(all_includes) -I$(top_srcdir)/include
+noinst_PROGRAMS = a5_test
+EXTRA_DIST = a5_test.ok
+
+a5_test_SOURCES = a5_test.c
+a5_test_LDADD = $(top_builddir)/src/libosmocore.la $(top_builddir)/src/gsm/libosmogsm.la
diff --git a/tests/a5/a5_test.c b/tests/a5/a5_test.c
new file mode 100644
index 00000000..14436f19
--- /dev/null
+++ b/tests/a5/a5_test.c
@@ -0,0 +1,98 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <osmocom/core/bits.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/gsm/a5.h>
+
+static const uint8_t key[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
+static const uint32_t fn = 123456;
+static const uint8_t dl[] = {
+ /* A5/0 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ /* A5/1 */
+ 0xcb, 0xa2, 0x55, 0x76, 0x17, 0x5d, 0x3b, 0x1c,
+ 0x7b, 0x2f, 0x29, 0xa8, 0xc1, 0xb6, 0x00,
+
+ /* A5/2 */
+ 0x45, 0x9c, 0x88, 0xc3, 0x82, 0xb7, 0xff, 0xb3,
+ 0x98, 0xd2, 0xf9, 0x6e, 0x0f, 0x14, 0x80,
+};
+static const uint8_t ul[] = {
+ /* A5/0 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ /* A5/1 */
+ 0xd9, 0x03, 0x5e, 0x0f, 0x2a, 0xec, 0x13, 0x9a,
+ 0x05, 0xd4, 0xa8, 0x7b, 0xb1, 0x64, 0x80,
+
+ /* A5/2 */
+ 0xf0, 0x3a, 0xac, 0xde, 0xe3, 0x5b, 0x5e, 0x65,
+ 0x80, 0xba, 0xab, 0xc0, 0x59, 0x26, 0x40,
+};
+
+static const char *
+binstr(ubit_t *d, int n)
+{
+ static char str[256];
+ int i;
+
+ for (i=0; i<n; i++)
+ str[i] = d[i] ? '1' : '0';
+
+ str[i] = '\0';
+
+ return str;
+}
+
+int main(int argc, char **argv)
+{
+ ubit_t exp[114];
+ ubit_t out[114];
+ int n, i;
+
+ for (n=0; n<3; n++) {
+ /* "Randomize" */
+ for (i=0; i<114; i++)
+ out[i] = i & 1;
+
+ /* DL */
+ osmo_pbit2ubit(exp, &dl[15*n], 114);
+
+ osmo_a5(n, key, fn, out, NULL);
+
+ printf("A5/%d - DL: %s", n, binstr(out, 114));
+
+ if (!memcmp(exp, out, 114))
+ printf(" => OK\n");
+ else {
+ printf(" => BAD\n");
+ printf(" Expected: %s", binstr(out, 114));
+ fprintf(stderr, "[!] A5/%d DL failed", n);
+ exit(1);
+ }
+
+ /* UL */
+ osmo_pbit2ubit(exp, &ul[15*n], 114);
+
+ osmo_a5(n, key, fn, NULL, out);
+
+ printf("A5/%d - UL: %s", n, binstr(out, 114));
+
+ if (!memcmp(exp, out, 114))
+ printf(" => OK\n");
+ else {
+ printf(" => BAD\n");
+ printf(" Expected: %s", binstr(out, 114));
+ fprintf(stderr, "[!] A5/%d UL failed", n);
+ exit(1);
+ }
+ }
+
+ return 0;
+}
diff --git a/tests/a5/a5_test.ok b/tests/a5/a5_test.ok
new file mode 100644
index 00000000..4497e14a
--- /dev/null
+++ b/tests/a5/a5_test.ok
@@ -0,0 +1,6 @@
+A5/0 - DL: 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 => OK
+A5/0 - UL: 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 => OK
+A5/1 - DL: 110010111010001001010101011101100001011101011101001110110001110001111011001011110010100110101000110000011011011000 => OK
+A5/1 - UL: 110110010000001101011110000011110010101011101100000100111001101000000101110101001010100001111011101100010110010010 => OK
+A5/2 - DL: 010001011001110010001000110000111000001010110111111111111011001110011000110100101111100101101110000011110001010010 => OK
+A5/2 - UL: 111100000011101010101100110111101110001101011011010111100110010110000000101110101010101111000000010110010010011001 => OK
diff --git a/tests/auth/Makefile.am b/tests/auth/Makefile.am
new file mode 100644
index 00000000..52976d02
--- /dev/null
+++ b/tests/auth/Makefile.am
@@ -0,0 +1,8 @@
+INCLUDES = $(all_includes) -I$(top_srcdir)/include
+noinst_PROGRAMS = milenage_test
+EXTRA_DIST = milenage_test.ok
+
+milenage_test_SOURCES = milenage_test.c
+milenage_test_LDADD = $(top_builddir)/src/libosmocore.la \
+ $(top_builddir)/src/gsm/libosmogsm.la
+
diff --git a/tests/auth/milenage_test.c b/tests/auth/milenage_test.c
new file mode 100644
index 00000000..7c996f02
--- /dev/null
+++ b/tests/auth/milenage_test.c
@@ -0,0 +1,98 @@
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#include <osmocom/crypt/auth.h>
+#include <osmocom/core/utils.h>
+
+static void dump_auth_vec(struct osmo_auth_vector *vec)
+{
+ printf("RAND:\t%s\n", osmo_hexdump(vec->rand, sizeof(vec->rand)));
+
+ if (vec->auth_types & OSMO_AUTH_TYPE_UMTS) {
+ printf("AUTN:\t%s\n", osmo_hexdump(vec->autn, sizeof(vec->autn)));
+ printf("IK:\t%s\n", osmo_hexdump(vec->ik, sizeof(vec->ik)));
+ printf("CK:\t%s\n", osmo_hexdump(vec->ck, sizeof(vec->ck)));
+ printf("RES:\t%s\n", osmo_hexdump(vec->res, vec->res_len));
+ }
+
+ if (vec->auth_types & OSMO_AUTH_TYPE_GSM) {
+ printf("SRES:\t%s\n", osmo_hexdump(vec->sres, sizeof(vec->sres)));
+ printf("Kc:\t%s\n", osmo_hexdump(vec->kc, sizeof(vec->kc)));
+ }
+}
+
+static struct osmo_sub_auth_data test_aud = {
+ .type = OSMO_AUTH_TYPE_UMTS,
+ .algo = OSMO_AUTH_ALG_MILENAGE,
+ .u.umts = {
+ .opc = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+ .k = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+ .amf = { 0x00, 0x00 },
+ .sqn = 0x22,
+ },
+};
+
+static int opc_test(const struct osmo_sub_auth_data *aud)
+{
+ int rc;
+ uint8_t opc[16];
+#if 0
+ const uint8_t op[16] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f };
+#else
+ const uint8_t op[16] = { 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0 };
+#endif
+
+ rc = milenage_opc_gen(opc, aud->u.umts.k, op);
+
+ printf("OP:\t%s\n", osmo_hexdump(op, sizeof(op)));
+ printf("OPC:\t%s\n", osmo_hexdump(opc, sizeof(opc)));
+ return rc;
+}
+
+int main(int argc, char **argv)
+{
+ struct osmo_auth_vector _vec;
+ struct osmo_auth_vector *vec = &_vec;
+ uint8_t _rand[16];
+ int rc;
+
+#if 0
+ srand(time(NULL));
+ *(uint32_t *)&_rand[0] = rand();
+ *(uint32_t *)(&_rand[4]) = rand();
+ *(uint32_t *)(&_rand[8]) = rand();
+ *(uint32_t *)(&_rand[12]) = rand();
+#else
+ memset(_rand, 0, sizeof(_rand));
+#endif
+ memset(vec, 0, sizeof(*vec));
+
+ rc = osmo_auth_gen_vec(vec, &test_aud, _rand);
+ if (rc < 0) {
+ fprintf(stderr, "error generating auth vector\n");
+ exit(1);
+ }
+
+ dump_auth_vec(vec);
+
+ const uint8_t auts[14] = { 0x87, 0x11, 0xa0, 0xec, 0x9e, 0x16, 0x37, 0xdf,
+ 0x17, 0xf8, 0x0b, 0x38, 0x4e, 0xe4 };
+
+ rc = osmo_auth_gen_vec_auts(vec, &test_aud, auts, _rand, _rand);
+ if (rc < 0) {
+ printf("AUTS failed\n");
+ } else {
+ printf("AUTS success: SEQ.MS = %lu\n", test_aud.u.umts.sqn);
+ }
+
+ opc_test(&test_aud);
+
+ exit(0);
+
+}
diff --git a/tests/auth/milenage_test.ok b/tests/auth/milenage_test.ok
new file mode 100644
index 00000000..00ffc222
--- /dev/null
+++ b/tests/auth/milenage_test.ok
@@ -0,0 +1,10 @@
+RAND: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+AUTN: ec 93 20 c2 c2 12 00 00 c8 b7 de 2a 34 49 f1 bd
+IK: 12 cb 2d d3 e0 ec 83 78 f6 fc 1d 60 6c 61 9f 47
+CK: 72 00 a1 84 d8 f2 c7 58 fb df 87 90 0d db f2 75
+RES: e9 fc 88 cc c8 a3 53 81
+SRES: 21 5f db 4d
+Kc: 6d e8 16 a7 59 a4 29 12
+AUTS success: SEQ.MS = 33
+OP: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+OPC: c6 a1 3b 37 87 8f 5b 82 6f 4f 81 62 a1 c8 d8 79
diff --git a/tests/bits/Makefile.am b/tests/bits/Makefile.am
new file mode 100644
index 00000000..d6fb2f2f
--- /dev/null
+++ b/tests/bits/Makefile.am
@@ -0,0 +1,7 @@
+INCLUDES = $(all_includes) -I$(top_srcdir)/include
+noinst_PROGRAMS = bitrev_test
+EXTRA_DIST = bitrev_test.ok
+
+bitrev_test_SOURCES = bitrev_test.c
+bitrev_test_LDADD = $(top_builddir)/src/libosmocore.la
+
diff --git a/tests/bits/bitrev_test.c b/tests/bits/bitrev_test.c
new file mode 100644
index 00000000..5eca990a
--- /dev/null
+++ b/tests/bits/bitrev_test.c
@@ -0,0 +1,36 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <osmocom/core/utils.h>
+#include <osmocom/core/bits.h>
+
+static const uint8_t input[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
+static const uint8_t exp_out[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
+
+int main(int argc, char **argv)
+{
+ uint8_t out[ARRAY_SIZE(input)];
+ unsigned int offs;
+
+ for (offs = 0; offs < sizeof(out); offs++) {
+ uint8_t *start = out + offs;
+ uint8_t len = sizeof(out) - offs;
+
+ memcpy(out, input, sizeof(out));
+
+ printf("INORDER: %s\n", osmo_hexdump(start, len));
+ osmo_revbytebits_buf(start, len);
+ printf("REVERSED: %s\n", osmo_hexdump(start, len));
+ if (memcmp(start, exp_out + offs, len)) {
+ printf("EXPECTED: %s\n", osmo_hexdump(exp_out+offs, len));
+ fprintf(stderr, "REVERSED != EXPECTED!\n");
+ exit(1);
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
diff --git a/tests/bits/bitrev_test.ok b/tests/bits/bitrev_test.ok
new file mode 100644
index 00000000..47f402f4
--- /dev/null
+++ b/tests/bits/bitrev_test.ok
@@ -0,0 +1,24 @@
+INORDER: 01 02 04 08 10 20 40 80
+REVERSED: 80 40 20 10 08 04 02 01
+
+INORDER: 02 04 08 10 20 40 80
+REVERSED: 40 20 10 08 04 02 01
+
+INORDER: 04 08 10 20 40 80
+REVERSED: 20 10 08 04 02 01
+
+INORDER: 08 10 20 40 80
+REVERSED: 10 08 04 02 01
+
+INORDER: 10 20 40 80
+REVERSED: 08 04 02 01
+
+INORDER: 20 40 80
+REVERSED: 04 02 01
+
+INORDER: 40 80
+REVERSED: 02 01
+
+INORDER: 80
+REVERSED: 01
+
diff --git a/tests/conv/Makefile.am b/tests/conv/Makefile.am
new file mode 100644
index 00000000..75cfec8d
--- /dev/null
+++ b/tests/conv/Makefile.am
@@ -0,0 +1,6 @@
+INCLUDES = $(all_includes) -I$(top_srcdir)/include
+noinst_PROGRAMS = conv_test
+EXTRA_DIST = conv_test.ok
+
+conv_test_SOURCES = conv_test.c
+conv_test_LDADD = $(top_builddir)/src/libosmocore.la
diff --git a/tests/conv/conv_test.c b/tests/conv/conv_test.c
new file mode 100644
index 00000000..54e043e9
--- /dev/null
+++ b/tests/conv/conv_test.c
@@ -0,0 +1,486 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <osmocom/core/bits.h>
+#include <osmocom/core/conv.h>
+#include <osmocom/core/utils.h>
+
+#define MAX_LEN_BITS 512
+#define MAX_LEN_BYTES (512/8)
+
+
+/* ------------------------------------------------------------------------ */
+/* Test codes */
+/* ------------------------------------------------------------------------ */
+
+/* GSM xCCH -> Non-recursive code, flushed, not punctured */
+static const uint8_t conv_gsm_xcch_next_output[][2] = {
+ { 0, 3 }, { 1, 2 }, { 0, 3 }, { 1, 2 },
+ { 3, 0 }, { 2, 1 }, { 3, 0 }, { 2, 1 },
+ { 3, 0 }, { 2, 1 }, { 3, 0 }, { 2, 1 },
+ { 0, 3 }, { 1, 2 }, { 0, 3 }, { 1, 2 },
+};
+
+static const uint8_t conv_gsm_xcch_next_state[][2] = {
+ { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 },
+ { 8, 9 }, { 10, 11 }, { 12, 13 }, { 14, 15 },
+ { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 },
+ { 8, 9 }, { 10, 11 }, { 12, 13 }, { 14, 15 },
+};
+
+static const struct osmo_conv_code conv_gsm_xcch = {
+ .N = 2,
+ .K = 5,
+ .len = 224,
+ .term = CONV_TERM_FLUSH,
+ .next_output = conv_gsm_xcch_next_output,
+ .next_state = conv_gsm_xcch_next_state,
+};
+
+
+/* GSM TCH/AFS 7.95 -> Recursive code, flushed, with puncturing */
+static const uint8_t conv_gsm_tch_afs_7_95_next_output[][2] = {
+ { 0, 7 }, { 3, 4 }, { 2, 5 }, { 1, 6 },
+ { 2, 5 }, { 1, 6 }, { 0, 7 }, { 3, 4 },
+ { 3, 4 }, { 0, 7 }, { 1, 6 }, { 2, 5 },
+ { 1, 6 }, { 2, 5 }, { 3, 4 }, { 0, 7 },
+ { 3, 4 }, { 0, 7 }, { 1, 6 }, { 2, 5 },
+ { 1, 6 }, { 2, 5 }, { 3, 4 }, { 0, 7 },
+ { 0, 7 }, { 3, 4 }, { 2, 5 }, { 1, 6 },
+ { 2, 5 }, { 1, 6 }, { 0, 7 }, { 3, 4 },
+ { 0, 7 }, { 3, 4 }, { 2, 5 }, { 1, 6 },
+ { 2, 5 }, { 1, 6 }, { 0, 7 }, { 3, 4 },
+ { 3, 4 }, { 0, 7 }, { 1, 6 }, { 2, 5 },
+ { 1, 6 }, { 2, 5 }, { 3, 4 }, { 0, 7 },
+ { 3, 4 }, { 0, 7 }, { 1, 6 }, { 2, 5 },
+ { 1, 6 }, { 2, 5 }, { 3, 4 }, { 0, 7 },
+ { 0, 7 }, { 3, 4 }, { 2, 5 }, { 1, 6 },
+ { 2, 5 }, { 1, 6 }, { 0, 7 }, { 3, 4 },
+};
+
+static const uint8_t conv_gsm_tch_afs_7_95_next_state[][2] = {
+ { 0, 1 }, { 2, 3 }, { 5, 4 }, { 7, 6 },
+ { 9, 8 }, { 11, 10 }, { 12, 13 }, { 14, 15 },
+ { 16, 17 }, { 18, 19 }, { 21, 20 }, { 23, 22 },
+ { 25, 24 }, { 27, 26 }, { 28, 29 }, { 30, 31 },
+ { 33, 32 }, { 35, 34 }, { 36, 37 }, { 38, 39 },
+ { 40, 41 }, { 42, 43 }, { 45, 44 }, { 47, 46 },
+ { 49, 48 }, { 51, 50 }, { 52, 53 }, { 54, 55 },
+ { 56, 57 }, { 58, 59 }, { 61, 60 }, { 63, 62 },
+ { 1, 0 }, { 3, 2 }, { 4, 5 }, { 6, 7 },
+ { 8, 9 }, { 10, 11 }, { 13, 12 }, { 15, 14 },
+ { 17, 16 }, { 19, 18 }, { 20, 21 }, { 22, 23 },
+ { 24, 25 }, { 26, 27 }, { 29, 28 }, { 31, 30 },
+ { 32, 33 }, { 34, 35 }, { 37, 36 }, { 39, 38 },
+ { 41, 40 }, { 43, 42 }, { 44, 45 }, { 46, 47 },
+ { 48, 49 }, { 50, 51 }, { 53, 52 }, { 55, 54 },
+ { 57, 56 }, { 59, 58 }, { 60, 61 }, { 62, 63 },
+};
+
+static const uint8_t conv_gsm_tch_afs_7_95_next_term_output[] = {
+ 0, 3, 5, 6, 5, 6, 0, 3, 3, 0, 6, 5, 6, 5, 3, 0,
+ 4, 7, 1, 2, 1, 2, 4, 7, 7, 4, 2, 1, 2, 1, 7, 4,
+ 7, 4, 2, 1, 2, 1, 7, 4, 4, 7, 1, 2, 1, 2, 4, 7,
+ 3, 0, 6, 5, 6, 5, 3, 0, 0, 3, 5, 6, 5, 6, 0, 3,
+};
+
+static const uint8_t conv_gsm_tch_afs_7_95_next_term_state[] = {
+ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30,
+ 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62,
+ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30,
+ 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62,
+};
+
+static int conv_gsm_tch_afs_7_95_puncture[] = {
+ 1, 2, 4, 5, 8, 22, 70, 118, 166, 214, 262, 310,
+ 317, 319, 325, 332, 334, 341, 343, 349, 356, 358, 365, 367,
+ 373, 380, 382, 385, 389, 391, 397, 404, 406, 409, 413, 415,
+ 421, 428, 430, 433, 437, 439, 445, 452, 454, 457, 461, 463,
+ 469, 476, 478, 481, 485, 487, 490, 493, 500, 502, 503, 505,
+ 506, 508, 509, 511, 512,
+ -1, /* end */
+};
+
+static const struct osmo_conv_code conv_gsm_tch_afs_7_95 = {
+ .N = 3,
+ .K = 7,
+ .len = 165,
+ .term = CONV_TERM_FLUSH,
+ .next_output = conv_gsm_tch_afs_7_95_next_output,
+ .next_state = conv_gsm_tch_afs_7_95_next_state,
+ .next_term_output = conv_gsm_tch_afs_7_95_next_term_output,
+ .next_term_state = conv_gsm_tch_afs_7_95_next_term_state,
+ .puncture = conv_gsm_tch_afs_7_95_puncture,
+};
+
+
+/* GMR-1 TCH3 Speech -> Non recursive code, tail-biting, punctured */
+static const uint8_t conv_gmr1_tch3_speech_next_output[][2] = {
+ { 0, 3 }, { 1, 2 }, { 3, 0 }, { 2, 1 },
+ { 3, 0 }, { 2, 1 }, { 0, 3 }, { 1, 2 },
+ { 0, 3 }, { 1, 2 }, { 3, 0 }, { 2, 1 },
+ { 3, 0 }, { 2, 1 }, { 0, 3 }, { 1, 2 },
+ { 2, 1 }, { 3, 0 }, { 1, 2 }, { 0, 3 },
+ { 1, 2 }, { 0, 3 }, { 2, 1 }, { 3, 0 },
+ { 2, 1 }, { 3, 0 }, { 1, 2 }, { 0, 3 },
+ { 1, 2 }, { 0, 3 }, { 2, 1 }, { 3, 0 },
+ { 3, 0 }, { 2, 1 }, { 0, 3 }, { 1, 2 },
+ { 0, 3 }, { 1, 2 }, { 3, 0 }, { 2, 1 },
+ { 3, 0 }, { 2, 1 }, { 0, 3 }, { 1, 2 },
+ { 0, 3 }, { 1, 2 }, { 3, 0 }, { 2, 1 },
+ { 1, 2 }, { 0, 3 }, { 2, 1 }, { 3, 0 },
+ { 2, 1 }, { 3, 0 }, { 1, 2 }, { 0, 3 },
+ { 1, 2 }, { 0, 3 }, { 2, 1 }, { 3, 0 },
+ { 2, 1 }, { 3, 0 }, { 1, 2 }, { 0, 3 },
+};
+
+static const uint8_t conv_gmr1_tch3_speech_next_state[][2] = {
+ { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 },
+ { 8, 9 }, { 10, 11 }, { 12, 13 }, { 14, 15 },
+ { 16, 17 }, { 18, 19 }, { 20, 21 }, { 22, 23 },
+ { 24, 25 }, { 26, 27 }, { 28, 29 }, { 30, 31 },
+ { 32, 33 }, { 34, 35 }, { 36, 37 }, { 38, 39 },
+ { 40, 41 }, { 42, 43 }, { 44, 45 }, { 46, 47 },
+ { 48, 49 }, { 50, 51 }, { 52, 53 }, { 54, 55 },
+ { 56, 57 }, { 58, 59 }, { 60, 61 }, { 62, 63 },
+ { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 },
+ { 8, 9 }, { 10, 11 }, { 12, 13 }, { 14, 15 },
+ { 16, 17 }, { 18, 19 }, { 20, 21 }, { 22, 23 },
+ { 24, 25 }, { 26, 27 }, { 28, 29 }, { 30, 31 },
+ { 32, 33 }, { 34, 35 }, { 36, 37 }, { 38, 39 },
+ { 40, 41 }, { 42, 43 }, { 44, 45 }, { 46, 47 },
+ { 48, 49 }, { 50, 51 }, { 52, 53 }, { 54, 55 },
+ { 56, 57 }, { 58, 59 }, { 60, 61 }, { 62, 63 },
+};
+
+static const int conv_gmr1_tch3_speech_puncture[] = {
+ 3, 7, 11, 15, 19, 23, 27, 31, 35, 39, 43, 47,
+ 51, 55, 59, 63, 67, 71, 75, 79, 83, 87, 91, 95,
+ -1, /* end */
+};
+
+static const struct osmo_conv_code conv_gmr1_tch3_speech = {
+ .N = 2,
+ .K = 7,
+ .len = 48,
+ .term = CONV_TERM_TAIL_BITING,
+ .next_output = conv_gmr1_tch3_speech_next_output,
+ .next_state = conv_gmr1_tch3_speech_next_state,
+ .puncture = conv_gmr1_tch3_speech_puncture,
+};
+
+
+/* WiMax FCH -> Non recursive code, tail-biting, non-punctured */
+static const uint8_t conv_wimax_fch_next_output[][2] = {
+ { 0, 3 }, { 2, 1 }, { 3, 0 }, { 1, 2 },
+ { 3, 0 }, { 1, 2 }, { 0, 3 }, { 2, 1 },
+ { 0, 3 }, { 2, 1 }, { 3, 0 }, { 1, 2 },
+ { 3, 0 }, { 1, 2 }, { 0, 3 }, { 2, 1 },
+ { 1, 2 }, { 3, 0 }, { 2, 1 }, { 0, 3 },
+ { 2, 1 }, { 0, 3 }, { 1, 2 }, { 3, 0 },
+ { 1, 2 }, { 3, 0 }, { 2, 1 }, { 0, 3 },
+ { 2, 1 }, { 0, 3 }, { 1, 2 }, { 3, 0 },
+ { 3, 0 }, { 1, 2 }, { 0, 3 }, { 2, 1 },
+ { 0, 3 }, { 2, 1 }, { 3, 0 }, { 1, 2 },
+ { 3, 0 }, { 1, 2 }, { 0, 3 }, { 2, 1 },
+ { 0, 3 }, { 2, 1 }, { 3, 0 }, { 1, 2 },
+ { 2, 1 }, { 0, 3 }, { 1, 2 }, { 3, 0 },
+ { 1, 2 }, { 3, 0 }, { 2, 1 }, { 0, 3 },
+ { 2, 1 }, { 0, 3 }, { 1, 2 }, { 3, 0 },
+ { 1, 2 }, { 3, 0 }, { 2, 1 }, { 0, 3 },
+};
+
+static const uint8_t conv_wimax_fch_next_state[][2] = {
+ { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 },
+ { 8, 9 }, { 10, 11 }, { 12, 13 }, { 14, 15 },
+ { 16, 17 }, { 18, 19 }, { 20, 21 }, { 22, 23 },
+ { 24, 25 }, { 26, 27 }, { 28, 29 }, { 30, 31 },
+ { 32, 33 }, { 34, 35 }, { 36, 37 }, { 38, 39 },
+ { 40, 41 }, { 42, 43 }, { 44, 45 }, { 46, 47 },
+ { 48, 49 }, { 50, 51 }, { 52, 53 }, { 54, 55 },
+ { 56, 57 }, { 58, 59 }, { 60, 61 }, { 62, 63 },
+ { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 },
+ { 8, 9 }, { 10, 11 }, { 12, 13 }, { 14, 15 },
+ { 16, 17 }, { 18, 19 }, { 20, 21 }, { 22, 23 },
+ { 24, 25 }, { 26, 27 }, { 28, 29 }, { 30, 31 },
+ { 32, 33 }, { 34, 35 }, { 36, 37 }, { 38, 39 },
+ { 40, 41 }, { 42, 43 }, { 44, 45 }, { 46, 47 },
+ { 48, 49 }, { 50, 51 }, { 52, 53 }, { 54, 55 },
+ { 56, 57 }, { 58, 59 }, { 60, 61 }, { 62, 63 },
+};
+
+static const struct osmo_conv_code conv_wimax_fch = {
+ .N = 2,
+ .K = 7,
+ .len = 48,
+ .term = CONV_TERM_TAIL_BITING,
+ .next_output = conv_wimax_fch_next_output,
+ .next_state = conv_wimax_fch_next_state,
+};
+
+
+/* Random code -> Non recursive code, direct truncation, non-punctured */
+static const struct osmo_conv_code conv_trunc = {
+ .N = 2,
+ .K = 5,
+ .len = 224,
+ .term = CONV_TERM_TRUNCATION,
+ .next_output = conv_gsm_xcch_next_output,
+ .next_state = conv_gsm_xcch_next_state,
+};
+
+
+/* ------------------------------------------------------------------------ */
+/* Test vectors */
+/* ------------------------------------------------------------------------ */
+
+struct conv_test_vector {
+ const char *name;
+ const struct osmo_conv_code *code;
+ int in_len;
+ int out_len;
+ int has_vec;
+ pbit_t vec_in[MAX_LEN_BYTES];
+ pbit_t vec_out[MAX_LEN_BYTES];
+};
+
+static const struct conv_test_vector tests[] = {
+ {
+ .name = "GSM xCCH (non-recursive, flushed, not punctured)",
+ .code = &conv_gsm_xcch,
+ .in_len = 224,
+ .out_len = 456,
+ .has_vec = 1,
+ .vec_in = { 0xf3, 0x1d, 0xb4, 0x0c, 0x4d, 0x1d, 0x9d, 0xae,
+ 0xc0, 0x0a, 0x42, 0x57, 0x13, 0x60, 0x80, 0x96,
+ 0xef, 0x23, 0x7e, 0x4c, 0x1d, 0x96, 0x24, 0x19,
+ 0x17, 0xf2, 0x44, 0x99 },
+ .vec_out = { 0xe9, 0x4d, 0x70, 0xab, 0xa2, 0x87, 0xf0, 0xe7,
+ 0x04, 0x14, 0x7c, 0xab, 0xaf, 0x6b, 0xa1, 0x16,
+ 0xeb, 0x30, 0x00, 0xde, 0xc8, 0xfd, 0x0b, 0x85,
+ 0x80, 0x41, 0x4a, 0xcc, 0xd3, 0xc0, 0xd0, 0xb6,
+ 0x26, 0xe5, 0x4e, 0x32, 0x49, 0x69, 0x38, 0x17,
+ 0x33, 0xab, 0xaf, 0xb6, 0xc1, 0x08, 0xf3, 0x9f,
+ 0x8c, 0x75, 0x6a, 0x4e, 0x08, 0xc4, 0x20, 0x5f,
+ 0x8f },
+ },
+ {
+ .name = "GSM TCH/AFS 7.95 (recursive, flushed, punctured)",
+ .code = &conv_gsm_tch_afs_7_95,
+ .in_len = 165,
+ .out_len = 448,
+ .has_vec = 1,
+ .vec_in = { 0x87, 0x66, 0xc3, 0x58, 0x09, 0xd4, 0x06, 0x59,
+ 0x10, 0xbf, 0x6b, 0x7f, 0xc8, 0xed, 0x72, 0xaa,
+ 0xc1, 0x3d, 0xf3, 0x1e, 0xb0 },
+ .vec_out = { 0x92, 0xbc, 0xde, 0xa0, 0xde, 0xbe, 0x01, 0x2f,
+ 0xbe, 0xe4, 0x61, 0x32, 0x4d, 0x4f, 0xdc, 0x41,
+ 0x43, 0x0d, 0x15, 0xe0, 0x23, 0xdd, 0x18, 0x91,
+ 0xe5, 0x36, 0x2d, 0xb7, 0xd9, 0x78, 0xb8, 0xb1,
+ 0xb7, 0xcb, 0x2f, 0xc0, 0x52, 0x8f, 0xe2, 0x8c,
+ 0x6f, 0xa6, 0x79, 0x88, 0xed, 0x0c, 0x2e, 0x9e,
+ 0xa1, 0x5f, 0x45, 0x4a, 0xfb, 0xe6, 0x5a, 0x9c },
+ },
+ {
+ .name = "GMR-1 TCH3 Speech (non-recursive, tail-biting, punctured)",
+ .code = &conv_gmr1_tch3_speech,
+ .in_len = 48,
+ .out_len = 72,
+ .has_vec = 1,
+ .vec_in = { 0x4d, 0xcb, 0xfc, 0x72, 0xf4, 0x8c },
+ .vec_out = { 0xc0, 0x86, 0x63, 0x4b, 0x8b, 0xd4, 0x6a, 0x76, 0xb2 },
+ },
+ {
+ .name = "WiMax FCH (non-recursive, tail-biting, not punctured)",
+ .code = &conv_wimax_fch,
+ .in_len = 48,
+ .out_len = 96,
+ .has_vec = 1,
+ .vec_in = { 0xfc, 0xa0, 0xa0, 0xfc, 0xa0, 0xa0 },
+ .vec_out = { 0x19, 0x42, 0x8a, 0xed, 0x21, 0xed, 0x19, 0x42,
+ 0x8a, 0xed, 0x21, 0xed },
+ },
+ {
+ .name = "??? (non-recursive, direct truncation, not punctured)",
+ .code = &conv_trunc,
+ .in_len = 224,
+ .out_len = 448,
+ .has_vec = 1,
+ .vec_in = { 0xe5, 0xe0, 0x85, 0x7e, 0xf7, 0x08, 0x19, 0x5a,
+ 0xb9, 0xad, 0x82, 0x37, 0x98, 0x8b, 0x26, 0xb9,
+ 0x81, 0x26, 0x9c, 0x75, 0xaf, 0xf3, 0xcb, 0x07,
+ 0xac, 0x63, 0xe2, 0x9c,
+ },
+ .vec_out = { 0xea, 0x3b, 0x55, 0x0c, 0xd3, 0xf7, 0x85, 0x69,
+ 0xe5, 0x79, 0x83, 0xd3, 0xc3, 0x9f, 0xb8, 0x61,
+ 0x21, 0x63, 0x51, 0x18, 0xac, 0xcd, 0x32, 0x49,
+ 0x53, 0x5c, 0x13, 0x1d, 0xbe, 0x05, 0x11, 0x63,
+ 0x5c, 0xc3, 0x42, 0x05, 0x1c, 0x68, 0x0a, 0xb4,
+ 0x61, 0x15, 0xaa, 0x4d, 0x94, 0xed, 0xb3, 0x3a,
+ 0x5d, 0x1b, 0x09, 0xc2, 0x99, 0x01, 0xec, 0x68 },
+ },
+ { /* end */ },
+};
+
+
+
+
+/* ------------------------------------------------------------------------ */
+/* Main */
+/* ------------------------------------------------------------------------ */
+
+static void
+fill_random(ubit_t *b, int n)
+{
+ int i;
+ for (i=0; i<n; i++)
+ b[i] = random() & 1;
+}
+
+static void
+ubit_to_sbit(sbit_t *dst, ubit_t *src, int n)
+{
+ int i;
+ for (i=0; i<n; i++)
+ dst[i] = src[i] ? -127 : 127;
+}
+
+static void
+sbit_to_ubit(ubit_t *dst, sbit_t *src, int n)
+{
+ int i;
+ for (i=0; i<n; i++)
+ dst[i] = src[i] < 0;
+}
+
+
+int main(int argc, char argv[])
+{
+ const struct conv_test_vector *tst;
+ ubit_t *bu0, *bu1;
+ sbit_t *bs;
+
+ srandom(time(NULL));
+
+ bu0 = mall