view trau-decode/parse-main.c @ 14:98c0881c2af0

tfo/find-is-hdr: move here from freecalypso-reveng This little program was developed in freecalypso-reveng Hg repository in 2023-03, when we didn't have a separate repository for network-side reverse eng, but now that we do have separate repositories for FreeCalypso (mobile side) vs network side reverse eng, move TFO RE work to the proper place.
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 24 May 2024 21:18:22 +0000
parents 4d1732e4a143
children
line wrap: on
line source

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

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>

static unsigned file_offset;

static enum {
	HUNT_FOR_0,
	HUNT_FOUND_0,
	GOT_8_ZEROS,
	SYNCED
} state;
static unsigned hunt_for_0_count, frame_pos_count;
static uint8_t in_frame_2bit[160], frame_bits[320], d_bits[260];

static void
unpack_dibits()
{
	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
collect_d_bits()
{
	bcopy(frame_bits + 33, d_bits, 15);
	bcopy(frame_bits + 49, d_bits + 15, 15);
	bcopy(frame_bits + 65, d_bits + 30, 15);
	bcopy(frame_bits + 81, d_bits + 45, 15);
	bcopy(frame_bits + 97, d_bits + 60, 15);
	bcopy(frame_bits + 113, d_bits + 75, 15);
	bcopy(frame_bits + 129, d_bits + 90, 15);
	bcopy(frame_bits + 145, d_bits + 105, 15);
	bcopy(frame_bits + 161, d_bits + 120, 15);
	bcopy(frame_bits + 177, d_bits + 135, 15);
	bcopy(frame_bits + 193, d_bits + 150, 15);
	bcopy(frame_bits + 209, d_bits + 165, 15);
	bcopy(frame_bits + 225, d_bits + 180, 15);
	bcopy(frame_bits + 241, d_bits + 195, 15);
	bcopy(frame_bits + 257, d_bits + 210, 15);
	bcopy(frame_bits + 273, d_bits + 225, 15);
	bcopy(frame_bits + 289, d_bits + 240, 15);
	bcopy(frame_bits + 305, d_bits + 255, 5);
}

static void
process_frame()
{
	unsigned c1_5, c6_11;

	printf("Frame at 0x%x:\n", file_offset - 159);
	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;
	}
	putchar('\n');
	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]);
	switch (c1_5) {
	case 0x02:
	case 0x1C:
		collect_d_bits();
		print_fr_frame(d_bits);
		break;
	case 0x1A:
		collect_d_bits();
		check_efr_crc(d_bits);
		print_efr_frame(d_bits);
		break;
	}
	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]);
}

static int
check_sync_zeros()
{
	int i;

	for (i = 0; i < 16; i++) {
		if (frame_bits[i])
			return 0;
	}
	return 1;
}

static int
check_sync_ones()
{
	int i;

	for (i = 1; i < 20; i++) {
		if (!frame_bits[i*16])
			return 0;
	}
	return 1;
}

static void
check_sync()
{
	if (check_sync_zeros() && check_sync_ones())
		return;
	printf("Bad frame sync, returning to hunt state\n");
	state = HUNT_FOR_0;
}

static void
byte_input(inb)
{
	switch (state) {
	case HUNT_FOR_0:
		if (inb != 0)
			return;
		state = HUNT_FOUND_0;
		hunt_for_0_count = 1;
		return;
	case HUNT_FOUND_0:
		if (inb != 0) {
			state = HUNT_FOR_0;
			return;
		}
		hunt_for_0_count++;
		if (hunt_for_0_count >= 8)
			state = GOT_8_ZEROS;
		return;
	case GOT_8_ZEROS:
		if (inb & 2) {
			printf("Found frame sync at file offset 0x%x\n",
				file_offset - 8);
			bzero(in_frame_2bit, 8);
			in_frame_2bit[8] = inb;
			frame_pos_count = 9;
			state = SYNCED;
			return;
		}
		if (inb != 0)
			state = HUNT_FOR_0;
		return;
	case SYNCED:
		in_frame_2bit[frame_pos_count++] = inb;
		if (frame_pos_count < 160)
			return;
		frame_pos_count = 0;
		unpack_dibits();
		process_frame();
		check_sync();
		return;
	default:
		fprintf(stderr, "BUG: bad sync state\n");
		abort();
	}
}

main(argc, argv)
	char **argv;
{
	FILE *inf;
	int subslot, right_shift;
	int inb;

	if (argc != 3) {
		fprintf(stderr, "usage: %s binfile subslot\n", argv[0]);
		exit(1);
	}
	inf = fopen(argv[1], "r");
	if (!inf) {
		perror(argv[1]);
		exit(1);
	}
	subslot = atoi(argv[2]);
	if (subslot < 0 || subslot > 3) {
		fprintf(stderr, "error: invalid subslot argument\n");
		exit(1);
	}
	right_shift = (3 - subslot) * 2;
	state = HUNT_FOR_0;
	for (file_offset = 0; ; file_offset++) {
		inb = getc(inf);
		if (inb < 0)
			break;
		inb >>= right_shift;
		inb &= 3;
		byte_input(inb);
	}
	exit(0);
}