diff mncc/call_setup.c @ 15:ccc5ab6d8388

first version of themwi-mncc for ThemWi2
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 26 Jun 2022 16:31:47 -0800
parents
children c6572f4c31d2
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mncc/call_setup.c	Sun Jun 26 16:31:47 2022 -0800
@@ -0,0 +1,220 @@
+/*
+ * In this module we implement setup of new calls: either new MO calls
+ * coming from GSM or new MT calls coming from a ThemWi call socket.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.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 "struct.h"
+#include "gsm_call.h"
+
+preen_msc_provided_number(nums)
+	struct gsm_mncc_number *nums;
+{
+	int len;
+
+	len = grok_number_string(nums->number, 0);
+	switch (len) {
+	case 4:
+		nums->type = GSM48_TON_NET_SPEC;
+		nums->plan = GSM48_NPI_PRIVATE;
+		break;
+	case 11:
+		if (nums->number[0] != '1')
+			return(0);
+		nums->type = GSM48_TON_INTERNATIONAL;
+		nums->plan = GSM48_NPI_ISDN_E164;
+		break;
+	default:
+		return(0);
+	}
+	nums->screen = GSM48_SCRN_NETWORK;
+	return(1);
+}
+
+void
+reject_mo_call(callref, cause_loc, cause_val)
+	uint32_t callref;
+{
+	struct gsm_mncc msg;
+
+	bzero(&msg, sizeof(struct gsm_mncc));
+	msg.msg_type = MNCC_REJ_REQ;
+	msg.callref = callref;
+	mncc_set_cause(&msg, cause_loc, cause_val);
+	send_mncc_to_gsm(&msg, sizeof(struct gsm_mncc));
+}
+
+void
+process_mo_call_setup(msg)
+	struct gsm_mncc *msg;
+{
+	struct gsm_call *call;
+	char nanp[11];
+	int res, is_nanp, is_itn, is_local;
+
+	if (preen_msc_provided_number(&msg->calling))
+		msg->fields |= MNCC_F_CALLING;
+	else
+		msg->fields &= ~MNCC_F_CALLING;
+	if (!(msg->fields & MNCC_F_CALLED)) {
+		reject_mo_call(msg->callref, GSM48_CAUSE_LOC_PRN_S_LU,
+				GSM48_CC_CAUSE_INVAL_MAND_INF);
+		return;
+	}
+	call = create_gsm_call(msg->callref);
+	if (!call) {
+		reject_mo_call(msg->callref, GSM48_CAUSE_LOC_PRN_S_LU,
+				GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
+		return;
+	}
+	/* route based on destination address */
+	refresh_number_db();
+	is_nanp = is_itn = 0;
+	switch (grok_number_string(msg->called.number, 0)) {
+	case 4:
+		if (msg->called.type != GSM48_TON_UNKNOWN &&
+		    msg->called.type != GSM48_TON_NET_SPEC &&
+		    msg->called.type != GSM48_TON_SHORT_CODE)
+			break;
+		if (msg->called.plan != GSM48_NPI_UNKNOWN &&
+		    msg->called.plan != GSM48_NPI_ISDN_E164 &&
+		    msg->called.plan != GSM48_NPI_PRIVATE)
+			break;
+		res = lookup_short_dial_number(msg->called.number, nanp);
+		if (!res) {
+			reject_mo_call(msg->callref, GSM48_CAUSE_LOC_PRN_S_LU,
+					GSM48_CC_CAUSE_UNASSIGNED_NR);
+			call->gc_flag = 1;
+			return;
+		}
+		if (nanp[0]) {
+			is_nanp = 1;
+			msg->called.type = GSM48_TON_INTERNATIONAL;
+			msg->called.plan = GSM48_NPI_ISDN_E164;
+			msg->called.number[0] = '1';
+			strcpy(msg->called.number+1, nanp);
+		} else {
+			is_itn = 1;
+			msg->called.type = GSM48_TON_NET_SPEC;
+			msg->called.plan = GSM48_NPI_PRIVATE;
+		}
+		break;
+	case 10:
+		if (msg->called.type != GSM48_TON_UNKNOWN &&
+		    msg->called.type != GSM48_TON_NATIONAL)
+			break;
+		if (msg->called.plan != GSM48_NPI_UNKNOWN &&
+		    msg->called.plan != GSM48_NPI_ISDN_E164 &&
+		    msg->called.plan != GSM48_NPI_NATIONAL)
+			break;
+		if (!is_nanp_valid_prefix(msg->called.number)) {
+			reject_mo_call(msg->callref, GSM48_CAUSE_LOC_PRN_S_LU,
+					GSM48_CC_CAUSE_INV_NR_FORMAT);
+			call->gc_flag = 1;
+			return;
+		}
+		is_nanp = 1;
+		/* canonicalize to international format */
+		bcopy(msg->called.number, msg->called.number+1, 11);
+		msg->called.number[0] = '1';
+		msg->called.type = GSM48_TON_INTERNATIONAL;
+		msg->called.plan = GSM48_NPI_ISDN_E164;
+		break;
+	case 11:
+		if (msg->called.type != GSM48_TON_UNKNOWN &&
+		    msg->called.type != GSM48_TON_INTERNATIONAL)
+			break;
+		if (msg->called.plan != GSM48_NPI_UNKNOWN &&
+		    msg->called.plan != GSM48_NPI_ISDN_E164)
+			break;
+		if (msg->called.number[0] != '1')
+			break;
+		if (!is_nanp_valid_prefix(msg->called.number+1)) {
+			reject_mo_call(msg->callref, GSM48_CAUSE_LOC_PRN_S_LU,
+					GSM48_CC_CAUSE_INV_NR_FORMAT);
+			call->gc_flag = 1;
+			return;
+		}
+		is_nanp = 1;
+		/* canonicalize to international format */
+		msg->called.type = GSM48_TON_INTERNATIONAL;
+		msg->called.plan = GSM48_NPI_ISDN_E164;
+		break;
+	}
+	is_local = is_itn;
+	if (is_nanp && is_nanp_locally_owned(msg->called.number+1))
+		is_local = 1;
+	/* weed out attempts to call yourself */
+	if (is_local && !strcmp(msg->calling.number, msg->called.number)) {
+		reject_mo_call(msg->callref, GSM48_CAUSE_LOC_PRN_S_LU,
+				GSM48_CC_CAUSE_INCOMPAT_DEST);
+		call->gc_flag = 1;
+		return;
+	}
+	/* actually route the call */
+	if (is_local) {
+		internal_switch_mo_setup(call, msg);
+		return;
+	}
+	/* outbound calls remain to be implemented */
+	reject_mo_call(msg->callref, GSM48_CAUSE_LOC_PRN_S_LU,
+			GSM48_CC_CAUSE_NO_ROUTE);
+	call->gc_flag = 1;
+}
+
+static void
+reject_mt_call(conn, callref, cause_loc, cause_val)
+	struct socket_conn *conn;
+	uint32_t callref;
+{
+	struct gsm_mncc msg;
+
+	bzero(&msg, sizeof(struct gsm_mncc));
+	msg.msg_type = MNCC_REJ_REQ;
+	msg.callref = callref;
+	mncc_set_cause(&msg, cause_loc, cause_val);
+	mncc_signal_to_socket_nocall(conn, &msg);
+}
+
+void
+process_ext_mtcall_setup(conn, msg)
+	struct socket_conn *conn;
+	struct gsm_mncc *msg;
+{
+	struct gsm_call *call;
+
+	if (!(msg->fields & MNCC_F_CALLED) && !msg->imsi[0]) {
+		reject_mt_call(conn, msg->callref, GSM48_CAUSE_LOC_PRN_S_LU,
+				GSM48_CC_CAUSE_INVAL_MAND_INF);
+		return;
+	}
+	call = create_new_mt_call();
+	if (!call) {
+		reject_mt_call(conn, msg->callref, GSM48_CAUSE_LOC_PRN_S_LU,
+				GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
+		return;
+	}
+	call->socket = conn;
+	call->socket_ref = msg->callref;
+	/* forward to GSM MNCC interface */
+	msg->callref = call->callref;
+	send_mncc_to_gsm(&msg, sizeof(struct gsm_mncc));
+}
+
+preen_connected_number(msg)
+	struct gsm_mncc *msg;
+{
+	if (preen_msc_provided_number(&msg->connected))
+		msg->fields |= MNCC_F_CONNECTED;
+	else
+		msg->fields &= ~MNCC_F_CONNECTED;
+}