diff mtctest/sig_handler.c @ 5:e7b192a5dee5

mtctest: initial import from old ThemWi
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 09 Jun 2024 00:58:38 +0000
parents
children 33d8b3177540
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mtctest/sig_handler.c	Sun Jun 09 00:58:38 2024 +0000
@@ -0,0 +1,403 @@
+/*
+ * 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/time.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;
+extern struct timeval cur_event_time;
+
+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
+print_sdp(sdp)
+	char *sdp;
+{
+	char *cp, *ep, *np;
+
+	for (cp = sdp; *cp; cp = np) {
+		ep = index(cp, '\n');
+		if (ep) {
+			*ep = '\0';
+			np = ep + 1;
+		} else
+			np = 0;
+		ep = index(cp, '\r');
+		if (ep)
+			*ep = '\0';
+		printf("%s %s\n", cp == sdp ? "SDP:" : "    ", cp);
+	}
+}
+
+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
+send_rtp_connect()
+{
+	struct gsm_mncc_rtp rtp;
+
+	printf("Sending MNCC_RTP_CONNECT\n");
+	bzero(&rtp, sizeof(struct gsm_mncc_rtp));
+	rtp.msg_type = MNCC_RTP_CONNECT;
+	rtp.callref = 1;
+	bcopy(&dummy_rtp_endp, &rtp.addr, sizeof(struct sockaddr_storage));
+	send_mncc_to_gsm(&rtp, sizeof(struct gsm_mncc_rtp));
+}
+
+static void
+handle_dtmf_time()
+{
+	static struct timeval last_dtmf_time;
+	struct timeval delta;
+	unsigned ms;
+
+	if (timerisset(&last_dtmf_time) &&
+	    timercmp(&cur_event_time, &last_dtmf_time, >)) {
+		timersub(&cur_event_time, &last_dtmf_time, &delta);
+		if (delta.tv_sec >= 2)
+			printf("Time since last DTMF event: %u s\n",
+				(unsigned) delta.tv_sec);
+		else {
+			ms = delta.tv_sec * 1000 + delta.tv_usec / 1000;
+			printf("Time since last DTMF event: %u ms\n", ms);
+		}
+	}
+	bcopy(&cur_event_time, &last_dtmf_time, sizeof(struct timeval));
+}
+
+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);
+		print_sdp(msg->sdp);
+		send_rtp_connect();
+		send_connect_ack();
+		return;
+	case MNCC_CALL_CONF_IND:
+		printf("MNCC_CALL_CONF_IND: call is confirmed\n");
+		print_fields(msg);
+		print_sdp(msg->sdp);
+		return;
+	case MNCC_ALERT_IND:
+		printf("MNCC_ALERT_IND: call is alerting\n");
+		print_fields(msg);
+		print_sdp(msg->sdp);
+		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);
+		handle_dtmf_time();
+		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");
+		handle_dtmf_time();
+		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_CNF;
+		send_mncc_to_gsm(msg, sizeof(struct gsm_mncc));
+		return;
+	case MNCC_RETRIEVE_IND:
+		printf("MNCC_RETRIEVE_IND: MS requests call retrieve\n");
+		send_rtp_connect();
+		msg->msg_type = MNCC_RETRIEVE_CNF;
+		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_msg(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);
+	}
+	switch (msg->msg_type) {
+	case MNCC_RTP_CREATE:
+		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);
+		print_sdp(msg->sdp);
+		return;
+	case MNCC_RTP_CONNECT:
+		printf("MNCC_RTP_CONNECT: error response\n");
+		return;
+	case MNCC_RTP_FREE:
+		printf("MNCC_RTP_FREE: bogon\n");
+		return;
+	}
+}
+
+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:
+	case MNCC_RTP_CONNECT:
+	case MNCC_RTP_FREE:
+		handle_rtp_msg(msg, msglen);
+		return;
+	default:
+		fprintf(stderr,
+			"error: received unexpected MNCC message type 0x%x\n",
+			msg->msg_type);
+		exit(1);
+	}
+}