diff sip-out/call_setup.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/call_setup.c@1bbe57df74f6
children e89619893c1e
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sip-out/call_setup.c	Tue Oct 11 23:04:01 2022 -0800
@@ -0,0 +1,171 @@
+/*
+ * In this module we implement our initial handling of MNCC_SETUP_IND.
+ */
+
+#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();
+
+extern int block_1900_numbers;
+extern struct call *call_list;
+
+static void
+reject_mo_call(mncc, callref, cause_loc, cause_val)
+	struct mncc_conn *mncc;
+	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_sock(mncc, &msg, sizeof(struct gsm_mncc));
+}
+
+static void
+send_call_proceeding(call)
+	struct call *call;
+{
+	struct gsm_mncc msg;
+
+	bzero(&msg, sizeof(struct gsm_mncc));
+	msg.msg_type = MNCC_CALL_PROC_REQ;
+	msg.callref = call->mncc_callref;
+	send_mncc_to_sock(call->mncc, &msg, sizeof(struct gsm_mncc));
+}
+
+void
+handle_setup_ind(mncc, msg, msglen)
+	struct mncc_conn *mncc;
+	struct gsm_mncc *msg;
+	unsigned msglen;
+{
+	struct call *call;
+	struct sip_out_dest *dest;
+	struct special_num_route *special_rt;
+	char to_sip_user[MAX_SIP_USER_PART+1];
+	int rc;
+
+	if (msglen != sizeof(struct gsm_mncc)) {
+		syslog(LOG_CRIT,
+			"FATAL: Rx MNCC_SETUP_IND has wrong length");
+		exit(1);
+	}
+	/* check for duplicates */
+	call = find_call_by_mncc_callref(mncc, 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;
+	}
+	if (!(msg->fields & MNCC_F_CALLED) ||
+	    !(msg->fields & MNCC_F_BEARER_CAP)) {
+		syslog(LOG_ERR, "rejecting MO call 0x%x: missing mandatory IE",
+			msg->callref);
+		reject_mo_call(mncc, msg->callref, GSM48_CAUSE_LOC_PRN_S_LU,
+				GSM48_CC_CAUSE_INVAL_MAND_INF);
+		return;
+	}
+	/* route based on destination address */
+	refresh_out_routes_db();
+	if (msg->called.type == GSM48_TON_INTERNATIONAL) {
+		rc = grok_number_string(msg->called.number, 0);
+		if (rc < 2 || rc > MAX_E164_NUMBER) {
+inv_nr_format:		reject_mo_call(mncc, msg->callref,
+					GSM48_CAUSE_LOC_PRN_S_LU,
+					GSM48_CC_CAUSE_INV_NR_FORMAT);
+			return;
+		}
+		if (msg->called.number[0] == '0')
+			goto inv_nr_format;
+		if (msg->called.number[0] == '1') {
+			if (rc != 11)
+				goto inv_nr_format;
+			if (!is_nanp_valid_prefix(msg->called.number+1))
+				goto inv_nr_format;
+			if (msg->called.number[1] == '9' &&
+			    msg->called.number[2] == '0' &&
+			    msg->called.number[3] == '0' &&
+			    block_1900_numbers) {
+call_barred:			reject_mo_call(mncc, msg->callref,
+						GSM48_CAUSE_LOC_PRN_S_LU,
+						GSM48_CC_CAUSE_OP_DET_BARRING);
+				return;
+			}
+		}
+		rc = route_e164_number(msg->called.number, &dest);
+		if (!rc) {
+no_route_to_dest:	reject_mo_call(mncc, msg->callref,
+					GSM48_CAUSE_LOC_PRN_S_LU,
+					GSM48_CC_CAUSE_NO_ROUTE);
+			return;
+		}
+		to_sip_user[0] = '+';
+		strcpy(to_sip_user+1, msg->called.number);
+	} else {
+		rc = route_special_number(msg->called.number, &dest,
+					  &special_rt);
+		if (!rc)
+			goto no_route_to_dest;
+		strcpy(to_sip_user, special_rt->sip_user);
+	}
+	/* validate From number */
+	if (!(msg->fields & MNCC_F_CALLING))
+		goto call_barred;
+	if (msg->calling.type != GSM48_TON_INTERNATIONAL)
+		goto call_barred;
+	if (grok_number_string(msg->calling.number, 0) != 11 ||
+	    msg->calling.number[0] != '1')
+		goto call_barred;
+	/* speech-only restriction */
+	if (msg->bearer_cap.transfer != GSM48_BCAP_ITCAP_SPEECH ||
+	    msg->bearer_cap.mode != GSM48_BCAP_TMOD_CIRCUIT) {
+		syslog(LOG_ERR, "rejecting MO call 0x%x: bad bearer cap",
+			msg->callref);
+		reject_mo_call(mncc, msg->callref, GSM48_CAUSE_LOC_PRN_S_LU,
+				GSM48_CC_CAUSE_BEARER_CA_UNAVAIL);
+		return;
+	}
+	/* TMGW must be up and running */
+	rc = connect_tmgw_socket();
+	if (rc < 0) {
+		reject_mo_call(mncc, msg->callref, GSM48_CAUSE_LOC_PRN_S_LU,
+				GSM48_CC_CAUSE_NETWORK_OOO);
+		return;
+	}
+	/* allocate struct call and being stateful processing */
+	call = malloc(sizeof(struct call));
+	if (!call) {
+		syslog(LOG_CRIT, "failed malloc for outbound call!");
+		reject_mo_call(mncc, msg->callref, GSM48_CAUSE_LOC_PRN_S_LU,
+				GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
+		return;
+	}
+	bzero(call, sizeof(struct call));
+	call->mncc = mncc;
+	call->mncc_callref = msg->callref;
+	call->from_user[0] = '+';
+	strcpy(call->from_user+1, msg->calling.number);
+	sprintf(call->to_uri, "sip:%s@%s", to_sip_user, dest->domain);
+	bcopy(&dest->sin, &call->udp_sin, sizeof(struct sockaddr_in));
+	call->next = call_list;
+	call_list = call;
+	send_call_proceeding(call);
+	call->overall_state = OVERALL_STATE_GSM_RTP;
+	call->mncc_state = MNCC_STATE_MO_PROC;
+}