changeset 107:c6ffb176eaed

trau-decode: new program trau-parse-n
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 21 Dec 2025 20:05:22 +0000
parents 028307356ba9
children f2009a354444
files .hgignore trau-decode/Makefile trau-decode/parse-new16.c
diffstat 3 files changed, 323 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Fri Nov 21 06:37:46 2025 +0000
+++ b/.hgignore	Sun Dec 21 20:05:22 2025 +0000
@@ -26,6 +26,7 @@
 ^trau-decode/trau-hr-dump-hex$
 ^trau-decode/trau-parse$
 ^trau-decode/trau-parse-hex$
+^trau-decode/trau-parse-n$
 ^trau-decode/trau-sync8$
 
 ^trau-files/.*\.dump$
--- a/trau-decode/Makefile	Fri Nov 21 06:37:46 2025 +0000
+++ b/trau-decode/Makefile	Sun Dec 21 20:05:22 2025 +0000
@@ -1,7 +1,8 @@
 CC=	gcc
 CFLAGS=	-O2
 PROGS=	dump-1bit tfo-parse-fr16 trau-amr8-dump trau-amr8-dump-hex trau-extr \
-	trau-hr-dump trau-hr-dump-hex trau-parse trau-parse-hex trau-sync8
+	trau-hr-dump trau-hr-dump-hex trau-parse trau-parse-hex trau-parse-n \
+	trau-sync8
 
 FR_OBJS=parse-fr.o parse-fr-common.o parse-efr.o
 HR_OBJS=gsmhr_unpack.o hr-guts.o
@@ -37,6 +38,9 @@
 trau-parse-hex:	crc8gen.o parse-hex16.o ${TRAU16_OBJS}
 	${CC} ${CFLAGS} -o $@ $^ -lgsmfr2 -lgsmefr
 
+trau-parse-n:	crc8gen.o parse-new16.o ${TRAU16_OBJS}
+	${CC} ${CFLAGS} -o $@ $^ -lgsmfr2 -lgsmefr
+
 trau-sync8:	trau-sync8.c
 	${CC} ${CFLAGS} -o $@ $@.c
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/trau-decode/parse-new16.c	Sun Dec 21 20:05:22 2025 +0000
@@ -0,0 +1,317 @@
+/*
+ * This program reads a 64 kbit/s timeslot recording file, examines one
+ * of the four 16 kbit/s subslots (selected), looks for GSM 08.60 TRAU
+ * frames, and dumps whatever it finds.  The present version is a new one,
+ * put together for the purpose of reverse-engineering Abis output from
+ * Nokia BTS, which exhibits more complex behaviour than what our original
+ * trau-parse program can analyze properly.
+ */
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+
+static uint8_t *filebuf;
+static unsigned total_size;
+
+static enum {
+	NOT_D144,
+	D144_SYNC,
+	D144_EDATA,
+} d144_state;
+
+static void
+read_ts_file(filename, subslot_arg)
+	char *filename, *subslot_arg;
+{
+	FILE *inf;
+	struct stat st;
+	int subslot, right_shift;
+	unsigned n;
+	uint8_t *dp;
+	int b;
+
+	inf = fopen(filename, "r");
+	if (!inf) {
+		perror(filename);
+		exit(1);
+	}
+	fstat(fileno(inf), &st);
+	if (!S_ISREG(st.st_mode)) {
+		fprintf(stderr, "error: %s is not a regular file\n", filename);
+		exit(1);
+	}
+	total_size = st.st_size;
+	if (total_size < 160) {
+		fprintf(stderr, "error: %s is too short\n", filename);
+		exit(1);
+	}
+	filebuf = malloc(total_size);
+	if (!filebuf) {
+		perror("malloc of file size");
+		exit(1);
+	}
+	subslot = atoi(subslot_arg);
+	if (subslot < 0 || subslot > 3) {
+		fprintf(stderr, "error: invalid subslot argument\n");
+		exit(1);
+	}
+	right_shift = (3 - subslot) * 2;
+	dp = filebuf;
+	for (n = 0; n < total_size; n++) {
+		b = getc(inf);
+		if (b < 0) {
+			fprintf(stderr,
+			"error: getc() returned EOF contrary to st_size\n");
+			exit(1);
+		}
+		*dp++ = (b >> right_shift) & 3;
+	}
+	fclose(inf);
+}
+
+static int
+check_sync(pos)
+	unsigned pos;
+{
+	uint8_t *cand = filebuf + pos;
+	unsigned n;
+
+	for (n = 0; n < 8; n++) {
+		if (cand[n])
+			return 0;
+	}
+	if (!(cand[8] & 2))
+		return 0;
+	if (cand[8] == 3 && cand[9] == 3 && cand[10] == 3 &&
+	    (d144_state == D144_SYNC || d144_state == D144_EDATA))
+		return 1;
+	for (n = 2; n < 20; n++) {
+		if (!(cand[n * 8] & 2))
+			return 0;
+	}
+	return 1;
+}
+
+static void
+unpack_dibits(in_frame_2bit, frame_bits)
+	uint8_t *in_frame_2bit, *frame_bits;
+{
+	int i, inb;
+	uint8_t *op;
+
+	op = frame_bits;
+	for (i = 0; i < 160; i++) {
+		inb = in_frame_2bit[i];
+		if (inb & 2)
+			*op++ = 1;
+		else
+			*op++ = 0;
+		if (inb & 1)
+			*op++ = 1;
+		else
+			*op++ = 0;
+	}
+}
+
+static unsigned
+bits_to_num(bits, nbits)
+	uint8_t *bits;
+	unsigned nbits;
+{
+	unsigned accum;
+	unsigned n;
+
+	accum = 0;
+	for (n = 0; n < nbits; n++) {
+		accum <<= 1;
+		if (*bits)
+			accum |= 1;
+		bits++;
+	}
+	return accum;
+}
+
+static void
+dump_raw_nibbles(dibits, num_dibits)
+	uint8_t *dibits;
+	unsigned num_dibits;
+{
+	uint8_t *sp = dibits;
+	unsigned remain = num_dibits;
+
+	if (remain >= 2) {
+		while (remain >= 2) {
+			printf("%x", (sp[0] << 2) | sp[1]);
+			sp += 2;
+			remain -= 2;
+		}
+		putchar('\n');
+	}
+	if (remain)
+		printf("dribble %u%u\n", (*sp & 2) >> 1, (*sp & 1) >> 0);
+}
+
+static int
+process_frame(pos)
+	unsigned pos;
+{
+	uint8_t *frame_2b = filebuf + pos;
+	uint8_t frame_bits[320];
+	unsigned c1_5, c6_11;
+
+	printf("Frame at 0x%x:\n", pos);
+	dump_raw_nibbles(frame_2b, 160);
+	unpack_dibits(frame_2b, frame_bits);
+	printf("  C1-C5: %u%u%u%u%u", frame_bits[17], frame_bits[18],
+		frame_bits[19], frame_bits[20], frame_bits[21]);
+	c1_5 = bits_to_num(frame_bits + 17, 5);
+	switch (c1_5) {
+	case 0x02:
+		fputs(" (FR UL)", stdout);
+		break;
+	case 0x1C:
+		fputs(" (FR DL)", stdout);
+		break;
+	case 0x1A:
+		fputs(" (EFR)", stdout);
+		break;
+	case 0x10:
+		fputs(" (idle UL)", stdout);
+		break;
+	case 0x0E:
+		fputs(" (idle DL)", stdout);
+		break;
+	case 0x08:
+		fputs(" (data UL)", stdout);
+		break;
+	case 0x16:
+		fputs(" (data DL)", stdout);
+		break;
+	case 0x09:
+		fputs(" (HR data UL)", stdout);
+		break;
+	case 0x17:
+		fputs(" (HR data DL)", stdout);
+		break;
+	case 0x14:
+		fputs(" (D144 sync)", stdout);
+		break;
+	case 0x1F:
+		fputs(" (E-TRAU)", stdout);
+		break;
+	case 0x06:
+		fputs(" (AMR)", stdout);
+		break;
+	}
+	putchar('\n');
+	if (c1_5 == 0x14)
+		d144_state = D144_SYNC;
+	else if (c1_5 == 0x1F &&
+		 (d144_state == D144_SYNC || d144_state == D144_EDATA))
+		d144_state = D144_EDATA;
+	else
+		d144_state = NOT_D144;
+	switch (c1_5) {
+	case 0x02:
+	case 0x1C:
+	case 0x1A:
+	case 0x10:
+	case 0x0E:
+		c6_11 = bits_to_num(frame_bits + 22, 6);
+		printf("  C6-C11: %u\n", c6_11);
+		printf("  C12=%u C13=%u C14=%u C15=%u\n", frame_bits[28],
+			frame_bits[29], frame_bits[30], frame_bits[31]);
+		print_fr_efr_frame(frame_bits, c1_5);
+		printf("  C16=%u C17=%u C18=%u C19=%u C20=%u C21=%u\n",
+			frame_bits[310], frame_bits[311], frame_bits[312],
+			frame_bits[313], frame_bits[314], frame_bits[315]);
+		printf("  T1=%u T2=%u T3=%u T4=%u\n", frame_bits[316],
+			frame_bits[317], frame_bits[318], frame_bits[319]);
+		return 1;
+	case 0x08:
+	case 0x09:
+	case 0x16:
+	case 0x17:
+	case 0x14:
+		print_data_frame(frame_bits);
+		return 0;
+	case 0x1F:
+		print_edata_frame(frame_bits);
+		return 0;
+	case 0x06:
+		print_amr_frame(frame_bits);
+		return 1;
+	default:
+		printf("  C6-C15: %u%u%u%u%u%u%u%u%u%u\n", frame_bits[22],
+			frame_bits[23], frame_bits[24], frame_bits[25],
+			frame_bits[26], frame_bits[27], frame_bits[28],
+			frame_bits[29], frame_bits[30], frame_bits[31]);
+		printf("  C16=%u C17=%u C18=%u C19=%u C20=%u C21=%u\n",
+			frame_bits[310], frame_bits[311], frame_bits[312],
+			frame_bits[313], frame_bits[314], frame_bits[315]);
+		printf("  T1=%u T2=%u T3=%u T4=%u\n", frame_bits[316],
+			frame_bits[317], frame_bits[318], frame_bits[319]);
+		return 0;
+	}
+}
+
+static void
+process_filebuf()
+{
+	unsigned p, nf_pos = 0, nf_accum = 0;
+	int match, have_t_bits;
+
+	d144_state = NOT_D144;
+	for (p = 0; p < total_size; ) {
+		if ((total_size - p) >= 160)
+			match = check_sync(p);
+		else
+			match = 0;
+		if (match) {
+			if (nf_accum) {
+				printf("Non-frame at 0x%x:\n", nf_pos);
+				dump_raw_nibbles(filebuf + nf_pos, nf_accum);
+			}
+			have_t_bits = process_frame(p);
+			if (have_t_bits && !filebuf[p+158] && !filebuf[p+159]) {
+				puts("advance of 250 us");
+				p += 158;
+			} else
+				p += 160;
+			nf_pos = p;
+			nf_accum = 0;
+		} else {
+			p++;
+			nf_accum++;
+			if (nf_accum >= 160) {
+				printf("Non-frame at 0x%x:\n", nf_pos);
+				dump_raw_nibbles(filebuf + nf_pos, nf_accum);
+				nf_pos = p;
+				nf_accum = 0;
+			}
+			d144_state = NOT_D144;
+		}
+	}
+	if (nf_accum) {
+		printf("Non-frame at 0x%x:\n", nf_pos);
+		dump_raw_nibbles(filebuf + nf_pos, nf_accum);
+	}
+}
+
+main(argc, argv)
+	char **argv;
+{
+	if (argc != 3) {
+		fprintf(stderr, "usage: %s r] binfile subslot\n", argv[0]);
+		exit(1);
+	}
+	read_ts_file(argv[1], argv[2]);
+	process_filebuf();
+	exit(0);
+}