view mtctest/sig_handler.c @ 39:64b9f0f90726

themwi-test-mtc: handle DTMF from MS
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 03 Sep 2022 14:44:19 -0800
parents e8e82a4bf12b
children 0967f67c6ac3
line wrap: on
line source

/*
 * In this module we handle all incoming messages from MNCC,
 * printing all of them and generating protocol-required responses
 * for some.
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "../include/mncc.h"
#include "../include/gsm48_const.h"

extern int disconnect_mode;
extern struct sockaddr_storage dummy_rtp_endp;

static void
print_bearer_cap(bcap)
	struct gsm_mncc_bearer_cap *bcap;
{
	int i, sv;

	printf("Bearer cap: itcap=%d tmod=%d coding=%d rrq=%d\n",
		bcap->transfer, bcap->mode, bcap->coding, bcap->radio);
	printf("  speech: CTM=%d sv", bcap->speech_ctm);
	for (i = 0; i < 8; i++) {
		sv = bcap->speech_ver[i];
		if (sv < 0)
			break;
		printf(" %d", sv);
	}
	putchar('\n');
	printf("  data: ra=%d sig=%d async=%d nstop=%d ndata=%d\n",
		bcap->data.rate_adaption, bcap->data.sig_access,
		bcap->data.async, bcap->data.nr_stop_bits,
		bcap->data.nr_data_bits);
	printf("  urate=%d par=%d irate=%d transp=%d mtype=%d\n",
		bcap->data.user_rate, bcap->data.parity,
		bcap->data.interm_rate, bcap->data.transp,
		bcap->data.modem_type);
}

static void
print_cc_cap(cc)
	struct gsm_mncc_cccap *cc;
{
	printf("CC capabilities: DTMF=%d PCP=%d\n", cc->dtmf, cc->pcp);
}

static void
print_cause(cause)
	struct gsm_mncc_cause *cause;
{
	int i;

	printf("Cause: loc=%d coding=%d value=%d", cause->location,
		cause->coding, cause->value);
	if (cause->rec)
		printf(" rec=0x%02X", cause->rec_val);
	for (i = 0; i < cause->diag_len; i++) {
		if (!(i & 15)) {
			putchar('\n');
			putchar(' ');
		}
		printf(" %02X", cause->diag[i] & 0xFF);
	}
	putchar('\n');
}

static void
print_progress(prog)
	struct gsm_mncc_progress *prog;
{
	printf("Progress: loc=%d coding=%d descr=0x%02X", prog->location,
		prog->coding, prog->descr);
}

static void
print_useruser(uu)
	struct gsm_mncc_useruser *uu;
{
	printf("User-User IE: proto=0x%02X\n", uu->proto);
	/* dump to be implemented if and when we actually get a UU somewhere */
}

static void
print_keypad(kp)
	int kp;
{
	if (kp >= '!' && kp <= '~')
		printf("Keypad code: %c\n", kp);
	else
		printf("Keypad code: 0x%02X\n", kp);
}

static void
print_facility(fac)
	struct gsm_mncc_facility *fac;
{
	int i;

	printf("Facility IE: %d byte(s)", fac->len);
	for (i = 0; i < fac->len; i++) {
		if (!(i & 15)) {
			putchar('\n');
			putchar(' ');
		}
		printf(" %02X", fac->info[i] & 0xFF);
	}
	putchar('\n');
}

static void
print_ssver(ssv)
	struct gsm_mncc_ssversion *ssv;
{
	int i;

	printf("SS version IE: %d byte(s)", ssv->len);
	for (i = 0; i < ssv->len; i++) {
		if (!(i & 15)) {
			putchar('\n');
			putchar(' ');
		}
		printf(" %02X", ssv->info[i] & 0xFF);
	}
	putchar('\n');
}

static void
print_fields(msg)
	struct gsm_mncc *msg;
{
	if (msg->fields & MNCC_F_BEARER_CAP)
		print_bearer_cap(&msg->bearer_cap);
	if (msg->fields & MNCC_F_CCCAP)
		print_cc_cap(&msg->cccap);
	if (msg->fields & MNCC_F_CAUSE)
		print_cause(&msg->cause);
	if (msg->fields & MNCC_F_PROGRESS)
		print_progress(&msg->progress);
	if (msg->fields & MNCC_F_USERUSER)
		print_useruser(&msg->useruser);
	if (msg->more)
		printf("More data flag set\n");
	if (msg->fields & MNCC_F_KEYPAD)
		print_keypad(msg->keypad);
	if (msg->fields & MNCC_F_FACILITY)
		print_facility(&msg->facility);
	if (msg->fields & MNCC_F_SSVERSION)
		print_ssver(&msg->ssversion);
}

static void
send_connect_ack()
{
	struct gsm_mncc ack;

	printf("Sending connect ack\n");
	bzero(&ack, sizeof(struct gsm_mncc));
	ack.msg_type = MNCC_SETUP_COMPL_REQ;
	ack.callref = 1;
	send_mncc_to_gsm(&ack, sizeof(struct gsm_mncc));
}

static void
handle_signaling_msg(msg, msglen)
	struct gsm_mncc *msg;
	unsigned msglen;
{
	if (msglen != sizeof(struct gsm_mncc)) {
		fprintf(stderr,
			"error: Rx MNCC message type 0x%x has wrong length\n",
			msg->msg_type);
		exit(1);
	}
	if (msg->callref != 1) {
		fprintf(stderr,
	"error: Rx MNCC message type 0x%x has unexpected callref 0x%x\n",
			msg->msg_type, msg->callref);
		exit(1);
	}
	switch (msg->msg_type) {
	case MNCC_SETUP_CNF:
		printf("MNCC_SETUP_CNF: call is answered\n");
		print_fields(msg);
		send_connect_ack();
		return;
	case MNCC_CALL_CONF_IND:
		printf("MNCC_CALL_CONF_IND: call is confirmed\n");
		print_fields(msg);
		return;
	case MNCC_ALERT_IND:
		printf("MNCC_ALERT_IND: call is alerting\n");
		print_fields(msg);
		return;
	case MNCC_NOTIFY_IND:
		printf("NNCC_NOTIFY_IND: NOTIFY byte from MS: 0x%02X\n",
			msg->notify);
		return;
	case MNCC_DISC_IND:
		printf("MNCC_DISC_IND: MS initiates disconnect\n");
		print_fields(msg);
		disconnect_mode = 1;
		printf("Responding with release request\n");
		msg->msg_type = MNCC_REL_REQ;
		send_mncc_to_gsm(msg, sizeof(struct gsm_mncc));
		return;
	case MNCC_FACILITY_IND:
		printf("MNCC_FACILITY_IND: call-related SS from MS\n");
		print_fields(msg);
		return;
	case MNCC_START_DTMF_IND:
		printf("MNCC_START_DTMF_IND: MS sending DTMF start\n");
		print_fields(msg);
		if (msg->fields & MNCC_F_KEYPAD &&
		    is_valid_dtmf_digit(msg->keypad)) {
			printf("Responding with ACK\n");
			msg->msg_type = MNCC_START_DTMF_RSP;
		} else {
			printf("Responding with Reject\n");
			msg->msg_type = MNCC_START_DTMF_REJ;
			mncc_set_cause(msg, GSM48_CAUSE_LOC_PRN_S_LU,
					GSM48_CC_CAUSE_INVAL_MAND_INF);
		}
		send_mncc_to_gsm(msg, sizeof(struct gsm_mncc));
		return;
	case MNCC_STOP_DTMF_IND:
		printf("MNCC_STOP_DTMF_IND: MS sending DTMF stop\n");
		msg->msg_type = MNCC_STOP_DTMF_RSP;
		send_mncc_to_gsm(msg, sizeof(struct gsm_mncc));
		return;
	case MNCC_MODIFY_IND:
		printf("MNCC_MODIFY_IND: MS requests call modification\n");
		print_fields(msg);
		msg->msg_type = MNCC_MODIFY_REJ;
		mncc_set_cause(msg, GSM48_CAUSE_LOC_PRN_S_LU,
				GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
		send_mncc_to_gsm(msg, sizeof(struct gsm_mncc));
		return;
	case MNCC_HOLD_IND:
		printf("MNCC_HOLD_IND: MS requests call hold\n");
		msg->msg_type = MNCC_HOLD_REJ;
		mncc_set_cause(msg, GSM48_CAUSE_LOC_PRN_S_LU,
				GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
		send_mncc_to_gsm(msg, sizeof(struct gsm_mncc));
		return;
	case MNCC_RETRIEVE_IND:
		printf("MNCC_RETRIEVE_IND: MS requests call retrieve\n");
		msg->msg_type = MNCC_RETRIEVE_REJ;
		mncc_set_cause(msg, GSM48_CAUSE_LOC_PRN_S_LU,
				GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
		send_mncc_to_gsm(msg, sizeof(struct gsm_mncc));
		return;
	case MNCC_USERINFO_IND:
		printf("MNCC_USERINFO_IND: user-user info\n");
		print_fields(msg);
		return;
	case MNCC_REL_IND:
		printf("MNCC_REL_IND: final release\n");
		print_fields(msg);
		exit(0);
	case MNCC_REL_CNF:
		printf("MNCC_REL_CNF: final release in response to request\n");
		print_fields(msg);
		exit(0);
	case MNCC_REJ_IND:
		printf("MNCC_REJ_IND: MT call rejected\n");
		print_fields(msg);
		exit(0);
	}
}

static void
handle_rtp_create(msg, msglen)
	struct gsm_mncc_rtp *msg;
	unsigned msglen;
{
	if (msglen != sizeof(struct gsm_mncc_rtp)) {
		fprintf(stderr,
			"error: Rx MNCC message type 0x%x has wrong length\n",
			msg->msg_type);
		exit(1);
	}
	if (msg->callref != 1) {
		fprintf(stderr,
	"error: Rx MNCC message type 0x%x has unexpected callref 0x%x\n",
			msg->msg_type, msg->callref);
		exit(1);
	}
	printf("MNCC_RTP_CREATE: RTP info from MSC\n");
	printf("payload_type=0x%x payload_msg_type=0x%x\n", msg->payload_type,
		msg->payload_msg_type);
	printf("Responding with MNCC_RTP_CONNECT (dummy RTP endpoint)\n");
	msg->msg_type = MNCC_RTP_CONNECT;
	bcopy(&dummy_rtp_endp, &msg->addr, sizeof(struct sockaddr_storage));
	send_mncc_to_gsm(msg, sizeof(struct gsm_mncc_rtp));
}

void
msg_from_mncc(msg, msglen)
	union mncc_msg *msg;
	unsigned msglen;
{
	switch (msg->msg_type) {
	case MNCC_SETUP_CNF:
	case MNCC_CALL_CONF_IND:
	case MNCC_ALERT_IND:
	case MNCC_NOTIFY_IND:
	case MNCC_DISC_IND:
	case MNCC_FACILITY_IND:
	case MNCC_START_DTMF_IND:
	case MNCC_STOP_DTMF_IND:
	case MNCC_MODIFY_IND:
	case MNCC_HOLD_IND:
	case MNCC_RETRIEVE_IND:
	case MNCC_USERINFO_IND:
	case MNCC_REL_IND:
	case MNCC_REL_CNF:
	case MNCC_REJ_IND:
		handle_signaling_msg(msg, msglen);
		return;
	case MNCC_RTP_CREATE:
		handle_rtp_create(msg, msglen);
		return;
	default:
		fprintf(stderr,
			"error: received unexpected MNCC message type 0x%x\n",
			msg->msg_type);
		exit(1);
	}
}