view mtctest/sig_handler.c @ 124:7e04d28fae8b

sip-in: default use-100rel to no BulkVS servers act badly when we send a reliable 180 Ringing response to an incoming call, even though they advertise 100rel support in the Supported header in the INVITE packet, and we probably won't be implementing 100rel for outbound because doing per-the-spec PRACK as a UAC is just too burdensome. Therefore, we need to consider 100rel extension as not-really-supported in themwi-system-sw.
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 01 Oct 2022 15:54:50 -0800
parents 64b9f0f90726
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);
	}
}