view rvinterf/old/format_g23.c @ 927:4e243402f453

rvinterf/lowlevel: use libprint for backslash-escape output
author Mychaela Falconia <falcon@freecalypso.org>
date Tue, 23 May 2023 03:59:42 +0000
parents e7502631a0f9
children
line wrap: on
line source

/*
 * This module implements the decoding of G23 trace packets into
 * human-readable form - or more precisely, traces, system primitives
 * and other packets that can be emitted through GPF on targets.
 * The decoding is based on my (Space Falcon's) understanding
 * of the packet format, which is in turn based on the GPF sources
 * available to us, now integrated under gsm-fw/gpf.
 */

#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include "../include/pktmux.h"
#include "../include/limits.h"

extern u_char rxpkt[];
extern size_t rxpkt_len;
extern char fmtbuf[];

static char *fmtbuf_ptr;

static int
basic_checks()
{
	int i, c;

	if (rxpkt_len < 17)
		return(0);
	/* check version bits in the header byte */
	if ((rxpkt[1] & 0xC0) != 0x80)
		return(0);
	/* check the length */
	c = rxpkt[2] | rxpkt[3] << 8;
	if (c + 4 != rxpkt_len)
		return(0);
	/* ensure that the "from" and "to" are printable ASCII */
	for (i = 8; i < 16; i++) {
		c = rxpkt[i];
		if (c < ' ' || c > '~')
			return(0);
	}
	/* basic checks pass */
	return(1);
}

static int
psprim_extra_checks()
{
	int i, c;

	if (rxpkt_len < 24)
		return(0);
	/* "original rcvr" field needs to be printable ASCII */
	for (i = 16; i < 20; i++) {
		c = rxpkt[i];
		if (c < ' ' || c > '~')
			return(0);
	}
	/* checks pass */
	return(1);
}

static void
print_malformed()
{
	int i;
	char *dp;

	dp = fmtbuf;
	strcpy(dp, "G23 UNK:");
	dp += 8;
	for (i = 1; i < rxpkt_len; i++) {
		sprintf(dp, " %02X", rxpkt[i]);
		dp += 3;
	}
	*dp = '\0';
	output_line(fmtbuf);
}

static int
entity_name_well_formed(p)
	char *p;
{
	int i, len;

	if (!isupper(p[0]))
		return(0);
	for (i = 0; i < 4; i++)
		if (!isalnum(p[i]))
			break;
	len = i;
	for (; i < 4; i++)
		if (p[i] != ' ')
			return(0);
	return(len);
}

static void
print_entity_name(raw)
	char *raw;
{
	int len;

	len = entity_name_well_formed(raw);
	if (len)
		sprintf(fmtbuf_ptr, "%.*s", len, raw);
	else
		sprintf(fmtbuf_ptr, "\"%.4s\"", raw);
	fmtbuf_ptr = index(fmtbuf_ptr, '\0');
}

static void
print_common_hdr(typestr)
	char *typestr;
{
	sprintf(fmtbuf, "G23 %s id=%02X ts=%02X%02X%02X%02X ", typestr,
		rxpkt[1], rxpkt[7], rxpkt[6], rxpkt[5], rxpkt[4]);
	fmtbuf_ptr = index(fmtbuf, '\0');
	print_entity_name(rxpkt + 8);
	*fmtbuf_ptr++ = '-';
	*fmtbuf_ptr++ = '>';
	print_entity_name(rxpkt + 12);
	*fmtbuf_ptr++ = ' ';
}

static void
format_text(start_off)
{
	int i, c;

	*fmtbuf_ptr++ = '\"';
	for (i = start_off; i < rxpkt_len; i++) {
		c = rxpkt[i];
		if (c & 0x80) {
			*fmtbuf_ptr++ = 'M';
			*fmtbuf_ptr++ = '-';
			c &= 0x7F;
		}
		if (c < 0x20) {
			*fmtbuf_ptr++ = '^';
			*fmtbuf_ptr++ = c + '@';
		} else if (c == 0x7F) {
			*fmtbuf_ptr++ = '^';
			*fmtbuf_ptr++ = '?';
		} else
			*fmtbuf_ptr++ = c;
	}
	*fmtbuf_ptr++ = '\"';
	*fmtbuf_ptr = '\0';
	output_line(fmtbuf);
}

static void
format_compressed_trace(start_off)
{
	int i;

	i = start_off + 1;
	sprintf(fmtbuf_ptr, "%d", rxpkt[i+1] << 8 | rxpkt[i]);
	fmtbuf_ptr = index(fmtbuf_ptr, '\0');
	i += 4;
	for (; i < rxpkt_len; i++) {
		sprintf(fmtbuf_ptr, " %02X", rxpkt[i]);
		fmtbuf_ptr += 3;
	}
	*fmtbuf_ptr = '\0';
	output_line(fmtbuf);
}

static void
format_trace()
{
	int i;

	i = 16;
	if (rxpkt[i] < 0x20) {
		sprintf(fmtbuf_ptr, "tc=%02X ", rxpkt[i]);
		fmtbuf_ptr += 6;
		i++;
	}
	if (rxpkt_len - i >= 5 && rxpkt[i] == '%' &&
	    !rxpkt[i+3] && !rxpkt[i+4])
		format_compressed_trace(i);
	else
		format_text(i);
}

static void
format_psprim()
{
	int i;

	/* original destination */
	*fmtbuf_ptr++ = '(';
	print_entity_name(rxpkt + 16);
	*fmtbuf_ptr++ = ')';
	/* opcode */
	sprintf(fmtbuf_ptr, " %02X%02X%02X%02X",
		rxpkt[23], rxpkt[22], rxpkt[21], rxpkt[20]);
	fmtbuf_ptr += 9;
	for (i = 24; i < rxpkt_len; i++) {
		sprintf(fmtbuf_ptr, " %02X", rxpkt[i]);
		fmtbuf_ptr += 3;
	}
	*fmtbuf_ptr = '\0';
	output_line(fmtbuf);
}

void
print_g23_trace()
{
	if (!basic_checks()) {
		print_malformed();
		return;
	}
	/* dispatch by type */
	switch (rxpkt[1] & 0x30) {
	case 0x10:
		/* PS primitive */
		if (psprim_extra_checks()) {
			print_common_hdr("PSprim");
			format_psprim();
		} else
			print_malformed();
		return;
	case 0x20:
		/* trace */
		print_common_hdr("trace");
		format_trace();
		return;
	case 0x30:
		/* system primitive */
		print_common_hdr("sysprim");
		format_text(16);
		return;
	default:
		print_malformed();
	}
}