diff sip-in/mgw_ops.c @ 141:e499e8db8b82

sip-in: handle call hold and retrieve
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 08 Oct 2022 13:28:30 -0800
parents 5685412bd6aa
children 0ecbc3dc8f93
line wrap: on
line diff
--- a/sip-in/mgw_ops.c	Sat Oct 08 11:48:26 2022 -0800
+++ b/sip-in/mgw_ops.c	Sat Oct 08 13:28:30 2022 -0800
@@ -14,6 +14,7 @@
 #include <strings.h>
 #include <syslog.h>
 #include "../include/gsm48_const.h"
+#include "../include/mncc.h"
 #include "../include/tmgw_ctrl.h"
 #include "../include/tmgw_const.h"
 #include "call.h"
@@ -87,6 +88,42 @@
 }
 
 void
+tmgw_send_mdcx_hold(call)
+	struct call *call;
+{
+	struct tmgw_ctrl_req req;
+
+	bzero(&req, sizeof req);
+	req.opcode = TMGW_CTRL_OP_MDCX;
+	req.transact_ref = get_new_tmgw_xact_id();
+	req.ep_id = call->mgw_ep_id;
+	req.setup_mask = TMGW_CTRL_MASK_FWD_MODE;
+	req.fwd_mode = TMGW_FWD_MODE_INACTIVE;
+	send_req_to_tmgw(&req);
+	call->mgw_state = MGW_STATE_HOLD_OP;
+	call->mgw_xact = TMGW_CTRL_OP_MDCX;
+	call->mgw_xact_id = req.transact_ref;
+}
+
+void
+tmgw_send_mdcx_retrieve(call)
+	struct call *call;
+{
+	struct tmgw_ctrl_req req;
+
+	bzero(&req, sizeof req);
+	req.opcode = TMGW_CTRL_OP_MDCX;
+	req.transact_ref = get_new_tmgw_xact_id();
+	req.ep_id = call->mgw_ep_id;
+	req.setup_mask = TMGW_CTRL_MASK_FWD_MODE;
+	req.fwd_mode = TMGW_FWD_MODE_SENDRECV;
+	send_req_to_tmgw(&req);
+	call->mgw_state = MGW_STATE_RETRIEVE_OP;
+	call->mgw_xact = TMGW_CTRL_OP_MDCX;
+	call->mgw_xact_id = req.transact_ref;
+}
+
+void
 tmgw_send_dlcx(call)
 	struct call *call;
 {
@@ -186,7 +223,7 @@
 }
 
 static void
-handle_mdcx_fail(call, msg)
+handle_mdcx_connect_fail(call, msg)
 	struct call *call;
 	struct tmgw_ctrl_resp *msg;
 {
@@ -212,7 +249,7 @@
 }
 
 static void
-mdcx_response(call, msg)
+mdcx_connect_response(call, msg)
 	struct call *call;
 	struct tmgw_ctrl_resp *msg;
 {
@@ -236,7 +273,7 @@
 		tmgw_send_dlcx(call);
 		switch (call->overall_state) {
 		case OVERALL_STATE_ANSWERED:
-			handle_mdcx_fail(call, msg);
+			handle_mdcx_connect_fail(call, msg);
 			return;
 		case OVERALL_STATE_TEARDOWN:
 			return;
@@ -246,6 +283,77 @@
 	}
 }
 
+static struct gsm_mncc_cause mgw_hold_retrieve_error = {
+	.coding		= GSM48_CAUSE_CODING_GSM,
+	.location	= GSM48_CAUSE_LOC_PRN_S_LU,
+	.value		= GSM48_CC_CAUSE_NETWORK_OOO,
+};
+
+static void
+mdcx_hold_response(call, msg)
+	struct call *call;
+	struct tmgw_ctrl_resp *msg;
+{
+	if (call->overall_state == OVERALL_STATE_TEARDOWN) {
+		tmgw_send_dlcx(call);
+		return;
+	}
+	if (msg->res == TMGW_RESP_OK) {
+		call->mgw_state = MGW_STATE_HELD;
+		mncc_send_hold_ack(call);
+	} else {
+		call->overall_state = OVERALL_STATE_TEARDOWN;
+		tmgw_send_dlcx(call);
+		disconnect_mncc(call, GSM48_CAUSE_LOC_PRN_S_LU,
+				GSM48_CC_CAUSE_NETWORK_OOO);
+		disconnect_sip(call, &mgw_hold_retrieve_error);
+	}
+}
+
+static void
+mdcx_retrieve_response(call, msg)
+	struct call *call;
+	struct tmgw_ctrl_resp *msg;
+{
+	if (call->overall_state == OVERALL_STATE_TEARDOWN) {
+		tmgw_send_dlcx(call);
+		return;
+	}
+	if (msg->res == TMGW_RESP_OK) {
+		call->mgw_state = MGW_STATE_COMPLETE;
+		mncc_send_retrieve_ack(call);
+	} else {
+		call->overall_state = OVERALL_STATE_TEARDOWN;
+		tmgw_send_dlcx(call);
+		disconnect_mncc(call, GSM48_CAUSE_LOC_PRN_S_LU,
+				GSM48_CC_CAUSE_NETWORK_OOO);
+		disconnect_sip(call, &mgw_hold_retrieve_error);
+	}
+}
+
+static void
+mdcx_response(call, msg)
+	struct call *call;
+	struct tmgw_ctrl_resp *msg;
+{
+	switch (call->mgw_state) {
+	case MGW_STATE_CONNECTING:
+		mdcx_connect_response(call, msg);
+		return;
+	case MGW_STATE_HOLD_OP:
+		mdcx_hold_response(call, msg);
+		return;
+	case MGW_STATE_RETRIEVE_OP:
+		mdcx_retrieve_response(call, msg);
+		return;
+	default:
+		syslog(LOG_CRIT,
+			"FATAL: invalid MGW state 0x%x on MDCX response",
+			call->mgw_state);
+		exit(1);
+	}
+}
+
 static void
 dlcx_response(call, msg)
 	struct call *call;