view uptools/sms-pdu-decode/sms-pdu-decode.c @ 505:7bf0d909c87e

fc-loadtool flash ID check: change of reset after the check logic This change only affects those flash configurations that have ID checks enabled. The logic for resetting the flash after the ID check has been changed as follows: 1) If the check fails, we return without attempting to reset the flash. 2) If the check is successful, we reset the flash using the configured method (could be AMD or Intel or Intel W30) instead of always doing an AMD flash reset as the original code did.
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 27 May 2019 19:58:01 +0000
parents 542c6d733772
children 9f7a263ad7f0
line wrap: on
line source

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

char *infname;
FILE *inf;
int ascii_ext_mode, global_hexdump_mode, keep_raw_pdu;

char input_line[1024];
u_char pdu[176], first_octet;
unsigned pdu_length, pdu_ptr;
int dcs_distilled;

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);
}

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);
}

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);
}

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

	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);
		gsm7_to_ascii_or_ext(alpha_gsm7, alpha_nsep, alpha_decoded,
				     (unsigned *) 0, ascii_ext_mode, 0,
				     (unsigned *) 0);
		printf("%s: \"%s\" (type 0x%02X)\n", direction, alpha_decoded,
			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);
}

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);
}

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);
}

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);
}

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);
}

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);
}

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);
}

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()
{
	unsigned udl, udl_octets;
	unsigned udhl, udh_octets, udh_chars, ud_chars;
	u_char ud7[160], decode_buf[321];
	int do_hexdump;
	unsigned decoded_len, badchars;

	if (handle_sca() < 0)
		return(-1);
	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 (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,
						     &badchars);
				break;
			case 16:
				ucs2_to_ascii_or_ext(pdu + pdu_ptr + udh_chars,
						     ud_chars,
						     decode_buf, &decoded_len,
						     ascii_ext_mode, 1,
						     &badchars);
				break;
			}
			printf("Length: %u", ud_chars);
			if (decoded_len != ud_chars)
				printf("->%u", decoded_len);
			if (badchars)
				printf(" (%u bad char%s)", badchars,
					badchars != 1 ? "s" : "");
			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);
}

process_cmdline(argc, argv)
	char **argv;
{
	int c;
	extern int optind;

	while ((c = getopt(argc, argv, "ehpu")) != EOF)
		switch (c) {
		case 'e':
			ascii_ext_mode = 1;
			continue;
		case 'h':
			global_hexdump_mode = 1;
			continue;
		case 'p':
			keep_raw_pdu = 1;
			continue;
		case 'u':
			ascii_ext_mode = 2;
			continue;
		default:
			fprintf(stderr, "%s: invalid option\n", argv[0]);
			exit(1);
		}
	if (argc > optind)
		infname = argv[optind];
}

swallow_empty_line()
{
	int c;

	c = getc(inf);
	if (c != '\n')
		ungetc(c, inf);
}

main(argc, argv)
	char **argv;
{
	char *nl;
	int lineno, cc;

	process_cmdline(argc, argv);
	if (infname) {
		inf = fopen(infname, "r");
		if (!inf) {
			perror(infname);
			exit(1);
		}
	} else {
		inf = stdin;
		infname = "stdin";
	}
	for (lineno = 1; fgets(input_line, sizeof input_line, inf); lineno++) {
		nl = index(input_line, '\n');
		if (!nl) {
			fprintf(stderr, "%s line %d: no newline\n",
				infname, lineno);
			exit(1);
		}
		*nl = '\0';
		cc = decode_hex_line(input_line, pdu, sizeof pdu);
		if (cc <= 0) {
			puts(input_line);
			continue;
		}
		pdu_length = cc;
		if (keep_raw_pdu)
			printf("%s\n\n", input_line);
		process_pdu();
		putchar('\n');
		swallow_empty_line();
	}
	exit(0);
}