view uptools/sms-pdu-decode/pdu-common.c @ 1014:961efadd530a default tip

fc-shell TCH DL handler: add support for CSD modes TCH DL capture mechanism in FC Tourmaline firmware has been extended to support CSD modes in addition to speech - add the necessary support on the host tools side. It needs to be noted that this mechanism in its present state does NOT provide the debug utility value that was sought: as we learned only after the code was implemented, TI's DSP has a misfeature in that the buffer we are reading (a_dd_0[]) is zeroed out when the IDS block is enabled, i.e., we are reading all zeros and not the real DL bits we were after. But since the code has already been written, we are keeping it - perhaps we can do some tests with IDS disabled.
author Mychaela Falconia <falcon@freecalypso.org>
date Tue, 26 Nov 2024 06:27:43 +0000
parents b515a97e5dff
children
line wrap: on
line source

#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>

int ascii_ext_mode, global_hexdump_mode;

u_char pdu[176];
unsigned pdu_length;

static u_char first_octet;
static unsigned pdu_ptr;
static int dcs_distilled;

static
handle_sca()
{
	unsigned sca_len;
	char digits[21];

	sca_len = pdu[0];
	pdu_ptr = 1;
	if (!sca_len)
		return(0);
	if (sca_len < 2 || sca_len > 11) {
		printf("Decode-Error: invalid SCA length\n");
		return(-1);
	}
	if (pdu_ptr + sca_len > pdu_length) {
		printf("Decode-Error: SCA goes past PDU end\n");
		return(-1);
	}
	pdu_ptr += sca_len;
	decode_address_digits(pdu + 2, digits, sc_addr_ndigits(pdu));
	printf("SCA: %s%s (type 0x%02X)\n", pdu[1] == 0x91 ? "+" : "", digits,
		pdu[1]);
	return(0);
}

static
handle_first_octet()
{
	if (pdu_ptr >= pdu_length) {
		printf("Decode-Error: end of PDU before FO\n");
		return(-1);
	}
	first_octet = pdu[pdu_ptr++];
	printf("First-Octet: 0x%02X\n", first_octet);
	return(0);
}

static
handle_mr()
{
	if (pdu_ptr >= pdu_length) {
		printf("Decode-Error: end of PDU before MR\n");
		return(-1);
	}
	printf("MR: 0x%02X\n", pdu[pdu_ptr++]);
	return(0);
}

static
handle_user_addr(direction)
	char *direction;
{
	unsigned addr_field_len, alpha_nsep;
	char digits[21];
	u_char alpha_gsm7[11];

	if (pdu_ptr >= pdu_length) {
		printf("Decode-Error: end of PDU before %s address\n",
			direction);
		return(-1);
	}
	if (pdu[pdu_ptr] > 20) {
		printf("Decode-Error: %s address > 20 digits\n", direction);
		return(-1);
	}
	addr_field_len = ((pdu[pdu_ptr] + 1) >> 1) + 2;
	if (pdu_ptr + addr_field_len > pdu_length) {
		printf("Decode-Error: %s address goes past PDU end\n",
			direction);
		return(-1);
	}
	if (!pdu[pdu_ptr])
		printf("%s: empty-addr (type 0x%02X)\n", direction,
			pdu[pdu_ptr+1]);
	else if ((pdu[pdu_ptr+1] & 0x70) == 0x50 &&
		 alpha_addr_valid(pdu[pdu_ptr], &alpha_nsep)) {
		gsm7_unpack(pdu + pdu_ptr + 2, alpha_gsm7, alpha_nsep);
		printf("%s: ", direction);
		print_gsm7_string_to_file(alpha_gsm7, alpha_nsep, stdout);
		printf(" (type 0x%02X)\n", pdu[pdu_ptr+1]);
	} else {
		decode_address_digits(pdu + pdu_ptr + 2, digits, pdu[pdu_ptr]);
		printf("%s: %s%s (type 0x%02X)\n", direction,
			pdu[pdu_ptr+1] == 0x91 ? "+" : "", digits,
			pdu[pdu_ptr+1]);
	}
	pdu_ptr += addr_field_len;
	return(0);
}

static
handle_pid()
{
	if (pdu_ptr >= pdu_length) {
		printf("Decode-Error: end of PDU before PID\n");
		return(-1);
	}
	printf("PID: 0x%02X\n", pdu[pdu_ptr++]);
	return(0);
}

static
handle_dcs()
{
	u_char dcs;
	char *strtype;

	if (pdu_ptr >= pdu_length) {
		printf("Decode-Error: end of PDU before DCS\n");
		return(-1);
	}
	dcs = pdu[pdu_ptr++];
	dcs_distilled = sms_dcs_classify(dcs);
	switch (dcs_distilled) {
	case 7:
		strtype = "7-bit";
		break;
	case 8:
		strtype = "raw octets";
		break;
	case 9:
		strtype = "compressed";
		break;
	case 16:
		strtype = "UCS-2";
		break;
	}
	printf("DCS: 0x%02X (%s)\n", dcs, strtype);
	return(0);
}

static
handle_scts()
{
	char str[21];

	if (pdu_ptr + 7 > pdu_length) {
		printf("Decode-Error: end of PDU before SCTS\n");
		return(-1);
	}
	gsm_timestamp_decode(pdu + pdu_ptr, str);
	printf("SC-Timestamp: %s\n", str);
	pdu_ptr += 7;
	return(0);
}

static
handle_vp_abs()
{
	char str[21];

	if (pdu_ptr + 7 > pdu_length) {
		printf("Decode-Error: end of PDU before VP-abs\n");
		return(-1);
	}
	gsm_timestamp_decode(pdu + pdu_ptr, str);
	printf("VP-Absolute: %s\n", str);
	pdu_ptr += 7;
	return(0);
}

static
handle_vp_rel()
{
	unsigned vprel, hours, min;

	if (pdu_ptr >= pdu_length) {
		printf("Decode-Error: end of PDU before VP-rel\n");
		return(-1);
	}
	vprel = pdu[pdu_ptr++];
	if (vprel <= 143) {
		min = (vprel + 1) * 5;
		goto hhmm;
	} else if (vprel <= 167) {
		min = (vprel - 143) * 30 + 12 * 60;
		goto hhmm;
	} else if (vprel <= 196) {
		printf("VP-Relative: %u days\n", vprel - 166);
		return(0);
	} else {
		printf("VP-Relative: %u weeks\n", vprel - 192);
		return(0);
	}

hhmm:	hours = min / 60;
	min %= 60;
	printf("VP-Relative:");
	if (hours)
		printf(" %u hour%s", hours, hours != 1 ? "s" : "");
	if (min)
		printf(" %u min", min);
	putchar('\n');
	return(0);
}

static
handle_vp_enh()
{
	if (pdu_ptr + 7 > pdu_length) {
		printf("Decode-Error: end of PDU before VP-enh\n");
		return(-1);
	}
	printf("VP-Enhanced: %02X %02X %02X %02X %02X %02X %02X\n",
		pdu[pdu_ptr], pdu[pdu_ptr+1], pdu[pdu_ptr+2], pdu[pdu_ptr+3],
		pdu[pdu_ptr+4], pdu[pdu_ptr+5], pdu[pdu_ptr+6]);
	pdu_ptr += 7;
	return(0);
}

static
handle_vp()
{
	int rc;

	switch (first_octet & 0x18) {
	case 0x00:
		rc = 0;
		break;
	case 0x08:
		rc = handle_vp_enh();
		break;
	case 0x10:
		rc = handle_vp_rel();
		break;
	case 0x18:
		rc = handle_vp_abs();
		break;
	}
	return(rc);
}

process_pdu(require_exact_length, expect_sca)
{
	unsigned udl, udl_octets;
	unsigned udhl, udh_octets, udh_chars, ud_chars;
	u_char ud7[160], decode_buf[481];
	int do_hexdump;
	unsigned decoded_len;

	if (expect_sca) {
		if (handle_sca() < 0)
			return(-1);
	} else
		pdu_ptr = 0;
	if (handle_first_octet() < 0)
		return(-1);
	if (first_octet & 2) {
		printf("Decode-Error: MTI not supported\n");
		return(-1);
	}
	if (first_octet & 1) {
		if (handle_mr() < 0)
			return(-1);
	}
	if (handle_user_addr(first_octet & 1 ? "To" : "From") < 0)
		return(-1);
	if (handle_pid() < 0)
		return(-1);
	if (handle_dcs() < 0)
		return(-1);
	if (first_octet & 1) {
		if (handle_vp() < 0)
			return(-1);
	} else {
		if (handle_scts() < 0)
			return(-1);
	}
	if (pdu_ptr >= pdu_length) {
		printf("Decode-Error: end of PDU before UDL\n");
		return(-1);
	}
	udl = pdu[pdu_ptr++];
	if (dcs_distilled == 7) {
		if (udl > 160) {
			printf("Decode-Error: UDL %u > 160\n", udl);
			return(-1);
		}
		udl_octets = (udl * 7 + 7) / 8;
	} else {
		if (udl > 140) {
			printf("Decode-Error: UDL %u > 140\n", udl);
			return(-1);
		}
		udl_octets = udl;
	}
	if (require_exact_length && pdu_length - pdu_ptr != udl_octets) {
		printf("Decode-Error: UD length in PDU %u != expected %u\n",
			pdu_length - pdu_ptr, udl_octets);
		return(-1);
	}
	if (first_octet & 0x40) {
		if (!udl) {
			printf("Decode-Error: UDHI set with UDL=0\n");
			return(-1);
		}
		udhl = pdu[pdu_ptr];
		udh_octets = udhl + 1;
		if (udh_octets > udl_octets) {
			printf("Decode-Error: UDHL exceeds UDL\n");
			return(-1);
		}
		printf("UDH-Length: %u\n", udhl);
		if (dcs_distilled == 7)
			udh_chars = (udh_octets * 8 + 6) / 7;
		else
			udh_chars = udh_octets;
	} else {
		udhl = 0;
		udh_octets = 0;
		udh_chars = 0;
	}
	if (udh_chars >= udl) {
		ud_chars = 0;
		printf("Length: 0\n");
	} else {
		ud_chars = udl - udh_chars;
		if (dcs_distilled == 7)
			gsm7_unpack(pdu + pdu_ptr, ud7, udl);
		if (global_hexdump_mode)
			do_hexdump = 1;
		else switch (dcs_distilled) {
		case 7:
			do_hexdump = 0;
			break;
		case 8:
		case 9:
			do_hexdump = 1;
			break;
		case 16:
			if (ud_chars & 1)
				do_hexdump = 1;
			else
				do_hexdump = 0;
			break;
		}
		if (do_hexdump)
			printf("Length: %u (raw)\n", ud_chars);
		else {
			switch (dcs_distilled) {
			case 7:
				gsm7_to_ascii_or_ext(ud7 + udh_chars, ud_chars,
						     decode_buf, &decoded_len,
						     ascii_ext_mode, 1);
				break;
			case 16:
				ucs2_to_ascii_or_ext(pdu + pdu_ptr + udh_chars,
						     ud_chars,
						     decode_buf, &decoded_len,
						     ascii_ext_mode, 1);
				break;
			}
			printf("Length: %u", ud_chars);
			if (decoded_len != ud_chars)
				printf("->%u", decoded_len);
			putchar('\n');
		}
	}

	if (udhl) {
		printf("\nUDH:\n");
		msg_bits_hexdump(pdu + pdu_ptr + 1, udhl);
	}
	if (!ud_chars)
		return(0);
	putchar('\n');
	if (do_hexdump) {
		if (dcs_distilled == 7)
			msg_bits_hexdump(ud7 + udh_chars, ud_chars);
		else
			msg_bits_hexdump(pdu + pdu_ptr + udh_chars, ud_chars);
	} else
		puts(decode_buf);
	return(0);
}