view mncc/mncc_recv.c @ 97:9aed16c30622

mgw p2g: set M bit when restarting forwarding after no-forward
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 25 Sep 2022 20:05:02 -0800
parents 660126bd5f59
children
line wrap: on
line source

/*
 * In this module we implement initial handling of MNCC messages
 * coming from OsmoMSC, dispatching them further as appropriate.
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <syslog.h>
#include "../include/mncc.h"
#include "struct.h"
#include "gsm_call.h"

extern char *mncc_msg_name();

static void
report_runt(msg)
	union mncc_msg *msg;
{
	syslog(LOG_CRIT, "MNCC message type 0x%x from GSM is too short!",
		msg->msg_type);
}

static void
handle_setup_ind(msg, msglen)
	struct gsm_mncc *msg;
	unsigned msglen;
{
	struct gsm_call *call;

	if (msglen < sizeof(struct gsm_mncc)) {
		report_runt(msg);
		return;
	}
	syslog(LOG_DEBUG, "Rx MNCC_SETUP_IND from GSM, callref=0x%x",
		msg->callref);
	call = find_gsm_callref(msg->callref);
	if (call) {
		syslog(LOG_ERR, "duplicate MNCC_SETUP_IND for callref 0x%x",
			msg->callref);
		/* drop it like OsmoMSC's mncc_builtin does */
		return;
	}
	/* further processing */
	process_mo_call_setup(msg);
}

static void
handle_signaling_msg(msg, msglen)
	struct gsm_mncc *msg;
	unsigned msglen;
{
	struct gsm_call *call;

	if (msglen < sizeof(struct gsm_mncc)) {
		report_runt(msg);
		return;
	}
	syslog(LOG_DEBUG, "Rx %s from GSM, callref=0x%x",
		mncc_msg_name(msg->msg_type), msg->callref);
	call = find_gsm_callref(msg->callref);
	if (!call) {
		syslog(LOG_ERR, "%s from GSM: callref 0x%x not found",
			mncc_msg_name(msg->msg_type), msg->callref);
		/* drop it like OsmoMSC's mncc_builtin does */
		return;
	}
	if (msg->msg_type == MNCC_SETUP_CNF)
		preen_connected_number(msg);
	/* dispatch according to internal switch or socket */
	if (call->socket)
		mncc_signal_to_socket(call, msg);
	else
		internal_switch_mncc(call, msg);
}

static void
handle_release_msg(msg, msglen)
	struct gsm_mncc *msg;
	unsigned msglen;
{
	struct gsm_call *call;

	if (msglen < sizeof(struct gsm_mncc)) {
		report_runt(msg);
		return;
	}
	syslog(LOG_DEBUG, "Rx %s from GSM, callref=0x%x",
		mncc_msg_name(msg->msg_type), msg->callref);
	call = find_gsm_callref(msg->callref);
	if (!call) {
		syslog(LOG_ERR, "%s from GSM: callref 0x%x not found",
			mncc_msg_name(msg->msg_type), msg->callref);
		/* drop it like OsmoMSC's mncc_builtin does */
		return;
	}
	/* dispatch according to internal switch or socket */
	if (call->socket) {
		mncc_signal_to_socket(call, msg);
		syslog(LOG_DEBUG,
		"clearing socket call: GSM callref 0x%x, socket ref 0x%x",
			call->callref, call->socket_ref);
		extsock_dec_refcount(call->socket);
		call->gc_flag = 1;
	} else
		internal_switch_mncc(call, msg);
}

static void
handle_rtp_msg(msg, msglen)
	struct gsm_mncc_rtp *msg;
	unsigned msglen;
{
	struct gsm_call *call;

	if (msglen < sizeof(struct gsm_mncc_rtp)) {
		report_runt(msg);
		return;
	}
	syslog(LOG_DEBUG, "Rx %s from GSM, callref=0x%x",
		mncc_msg_name(msg->msg_type), msg->callref);
	call = find_gsm_callref(msg->callref);
	if (!call) {
		syslog(LOG_ERR, "%s from GSM: callref 0x%x not found",
			mncc_msg_name(msg->msg_type), msg->callref);
		/* drop it like OsmoMSC's mncc_builtin does */
		return;
	}
	/* only for socket connections - no RTP handling for internal */
	if (call->socket)
		mncc_rtp_to_socket(call, msg);
}

static void
handle_mncc_hello(msg, msglen)
	struct gsm_mncc_hello *msg;
	unsigned msglen;
{
	if (msglen < sizeof(struct gsm_mncc_hello)) {
		syslog(LOG_CRIT, "MNCC_SOCKET_HELLO message is too short!");
		exit(1);
	}
	if (msg->version != MNCC_SOCK_VERSION) {
		syslog(LOG_CRIT, "MNCC hello error: version number mismatch");
		exit(1);
	}
	if (msg->mncc_size != sizeof(struct gsm_mncc)) {
		syslog(LOG_CRIT, "MNCC hello error: mncc_size mismatch");
		exit(1);
	}
}

void
mncc_msg_from_gsm(msg, msglen)
	union mncc_msg *msg;
	unsigned msglen;
{
	switch (msg->msg_type) {
	case MNCC_SETUP_IND:
		handle_setup_ind(msg, msglen);
		return;
	case MNCC_SETUP_CNF:
	case MNCC_SETUP_COMPL_IND:
	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_MODIFY_CNF:
	case MNCC_MODIFY_REJ:
	case MNCC_HOLD_IND:
	case MNCC_RETRIEVE_IND:
	case MNCC_USERINFO_IND:
		handle_signaling_msg(msg, msglen);
		return;
	case MNCC_REL_IND:
	case MNCC_REL_CNF:
	case MNCC_REJ_IND:
		handle_release_msg(msg, msglen);
		return;
	case MNCC_RTP_CREATE:
	case MNCC_RTP_CONNECT:
	case MNCC_RTP_FREE:
		handle_rtp_msg(msg, msglen);
		return;
	case MNCC_SOCKET_HELLO:
		handle_mncc_hello(msg, msglen);
		return;
	default:
		syslog(LOG_CRIT, "unknown MNCC message type 0x%x from GSM",
			msg->msg_type);
	}
}