diff sip-out/mncc_sig_in.c @ 154:e54b0a9e322f

beginning of themwi-sip-out
author Mychaela Falconia <falcon@freecalypso.org>
date Tue, 11 Oct 2022 23:04:01 -0800
parents sip-in/mncc_handle.c@99fd4ae573ae
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sip-out/mncc_sig_in.c	Tue Oct 11 23:04:01 2022 -0800
@@ -0,0 +1,214 @@
+/*
+ * In this module we implement our handling of call control messages
+ * from OsmoMSC relayed to us via themwi-mncc.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <syslog.h>
+#include "../include/mncc.h"
+#include "../include/gsm48_const.h"
+#include "../include/out_routes.h"
+#include "call.h"
+
+extern struct call *find_call_by_mncc_callref();
+
+static void
+handle_disconnect_ind(call, msg)
+	struct call *call;
+	struct gsm_mncc *msg;
+{
+	/* release back to MNCC */
+	msg->msg_type = MNCC_REL_REQ;
+	send_mncc_to_sock(call->mncc, msg, sizeof(struct gsm_mncc));
+	call->mncc_state = MNCC_STATE_RELEASE;
+	/* signal disconnect to SIP */
+	call->overall_state = OVERALL_STATE_TEARDOWN;
+	disconnect_sip(call);
+	disconnect_tmgw(call);
+}
+
+static void
+handle_final_release(call, msg)
+	struct call *call;
+	struct gsm_mncc *msg;
+{
+	/* MNCC call leg is gone */
+	call->mncc = 0;
+	/* signal disconnect to SIP */
+	call->overall_state = OVERALL_STATE_TEARDOWN;
+	disconnect_sip(call);
+	disconnect_tmgw(call);
+	check_dead_call(call);
+}
+
+static void
+handle_dtmf_start(call, msg)
+	struct call *call;
+	struct gsm_mncc *msg;
+{
+	if (!(msg->fields & MNCC_F_KEYPAD) ||
+	    !is_valid_dtmf_digit(msg->keypad)) {
+		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_sock(call->mncc, msg, sizeof(struct gsm_mncc));
+		return;
+	}
+	if (call->mncc_state != MNCC_STATE_CONNECTED ||
+	    call->mgw_state != MGW_STATE_COMPLETE) {
+		msg->msg_type = MNCC_START_DTMF_REJ;
+		mncc_set_cause(msg, GSM48_CAUSE_LOC_PRN_S_LU,
+				GSM48_CC_CAUSE_MSGTYPE_INCOMPAT);
+		send_mncc_to_sock(call->mncc, msg, sizeof(struct gsm_mncc));
+		return;
+	}
+	call->dtmf_digit = msg->keypad;
+	tmgw_send_dtmf_start(call);
+}
+
+static void
+handle_dtmf_stop(call, msg)
+	struct call *call;
+	struct gsm_mncc *msg;
+{
+	if (call->mncc_state != MNCC_STATE_CONNECTED)
+		return;
+	if (call->mgw_state == MGW_STATE_COMPLETE)
+		tmgw_send_dtmf_stop(call);
+	else if (call->mgw_state == MGW_STATE_DTMF_OP)
+		call->dtmf_pending_stop = 1;
+	else {
+		/* dummy OK response */
+		msg->msg_type = MNCC_STOP_DTMF_RSP;
+		send_mncc_to_sock(call->mncc, msg, sizeof(struct gsm_mncc));
+	}
+}
+
+static void
+handle_call_hold(call, msg)
+	struct call *call;
+	struct gsm_mncc *msg;
+{
+	if (call->mncc_state != MNCC_STATE_CONNECTED ||
+	    call->mgw_state != MGW_STATE_COMPLETE) {
+		msg->msg_type = MNCC_HOLD_REJ;
+		mncc_set_cause(msg, GSM48_CAUSE_LOC_PRN_S_LU,
+				GSM48_CC_CAUSE_MSGTYPE_INCOMPAT);
+		send_mncc_to_sock(call->mncc, msg, sizeof(struct gsm_mncc));
+		return;
+	}
+	tmgw_send_mdcx_hold(call);
+}
+
+static void
+handle_call_retrieve(call, msg)
+	struct call *call;
+	struct gsm_mncc *msg;
+{
+	if (call->mncc_state != MNCC_STATE_CONNECTED ||
+	    call->mgw_state != MGW_STATE_HELD) {
+		msg->msg_type = MNCC_RETRIEVE_REJ;
+		mncc_set_cause(msg, GSM48_CAUSE_LOC_PRN_S_LU,
+				GSM48_CC_CAUSE_MSGTYPE_INCOMPAT);
+		send_mncc_to_sock(call->mncc, msg, sizeof(struct gsm_mncc));
+		return;
+	}
+	send_rtp_connect(call);
+	tmgw_send_mdcx_retrieve(call);
+}
+
+void
+handle_mncc_signal(mncc, msg, msglen)
+	struct mncc_conn *mncc;
+	struct gsm_mncc *msg;
+	unsigned msglen;
+{
+	struct call *call;
+
+	if (msglen != sizeof(struct gsm_mncc)) {
+		syslog(LOG_CRIT,
+			"FATAL: Rx MNCC message type 0x%x has wrong length",
+			msg->msg_type);
+		exit(1);
+	}
+	call = find_call_by_mncc_callref(mncc, msg->callref);
+	if (!call) {
+		syslog(LOG_CRIT,
+		"error: Rx MNCC message type 0x%x has invalid callref 0x%x",
+			msg->msg_type, msg->callref);
+		exit(1);
+	}
+	switch (msg->msg_type) {
+	case MNCC_DISC_IND:
+		handle_disconnect_ind(call, msg);
+		return;
+	case MNCC_REL_IND:
+	case MNCC_REL_CNF:
+		handle_final_release(call, msg);
+		return;
+	case MNCC_START_DTMF_IND:
+		handle_dtmf_start(call, msg);
+		return;
+	case MNCC_STOP_DTMF_IND:
+		handle_dtmf_stop(call, msg);
+		return;
+	case MNCC_MODIFY_IND:
+		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_sock(mncc, msg, sizeof(struct gsm_mncc));
+		return;
+	case MNCC_HOLD_IND:
+		handle_call_hold(call, msg);
+		return;
+	case MNCC_RETRIEVE_IND:
+		handle_call_retrieve(call, msg);
+		return;
+	}
+}
+
+void
+handle_rtp_create(mncc, msg, msglen)
+	struct mncc_conn *mncc;
+	struct gsm_mncc_rtp *msg;
+	unsigned msglen;
+{
+	struct call *call;
+
+	if (msglen != sizeof(struct gsm_mncc_rtp)) {
+		syslog(LOG_CRIT,
+			"FATAL: Rx MNCC message type 0x%x has wrong length",
+			msg->msg_type);
+		exit(1);
+	}
+	call = find_call_by_mncc_callref(mncc, msg->callref);
+	if (!call) {
+		syslog(LOG_CRIT,
+		"error: Rx MNCC message type 0x%x has invalid callref 0x%x",
+			msg->msg_type, msg->callref);
+		exit(1);
+	}
+	/* we need to be in the right state */
+	if (call->mncc_state != MNCC_STATE_MO_PROC) {
+		syslog(LOG_ERR,
+		"duplicate MNCC_RTP_CREATE for MO callref 0x%x, ignoring",
+			msg->callref);
+		return;
+	}
+	/* save Osmocom network RTP information */
+	bcopy(&msg->addr, &call->gsm_rtp_osmo, sizeof(struct sockaddr_storage));
+	call->gsm_payload_type = msg->payload_type;
+	call->gsm_payload_msg_type = msg->payload_msg_type;
+	/* move forward */
+	call->mncc_state = MNCC_STATE_GOT_RTP;
+	call->overall_state = OVERALL_STATE_CRCX;
+	tmgw_send_crcx(call);
+}