# HG changeset patch # User Mychaela Falconia # Date 1665264510 28800 # Node ID e499e8db8b82ed4cb7ab12d6aece91eaa36d2c79 # Parent 01fe81914bd6995e51b780ecc8e16fec22047611 sip-in: handle call hold and retrieve diff -r 01fe81914bd6 -r e499e8db8b82 sip-in/call.h --- a/sip-in/call.h Sat Oct 08 11:48:26 2022 -0800 +++ b/sip-in/call.h Sat Oct 08 13:28:30 2022 -0800 @@ -78,3 +78,6 @@ #define MGW_STATE_COMPLETE 3 #define MGW_STATE_DELETING 4 #define MGW_STATE_DTMF_OP 5 +#define MGW_STATE_HELD 6 +#define MGW_STATE_HOLD_OP 7 +#define MGW_STATE_RETRIEVE_OP 8 diff -r 01fe81914bd6 -r e499e8db8b82 sip-in/disconnect.c --- a/sip-in/disconnect.c Sat Oct 08 11:48:26 2022 -0800 +++ b/sip-in/disconnect.c Sat Oct 08 13:28:30 2022 -0800 @@ -45,9 +45,12 @@ case MGW_STATE_CONNECTING: case MGW_STATE_DELETING: case MGW_STATE_DTMF_OP: + case MGW_STATE_HOLD_OP: + case MGW_STATE_RETRIEVE_OP: return; case MGW_STATE_ALLOCATED: case MGW_STATE_COMPLETE: + case MGW_STATE_HELD: tmgw_send_dlcx(call); return; default: diff -r 01fe81914bd6 -r e499e8db8b82 sip-in/mgw_ops.c --- 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 #include #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; diff -r 01fe81914bd6 -r e499e8db8b82 sip-in/mncc_handle.c --- a/sip-in/mncc_handle.c Sat Oct 08 11:48:26 2022 -0800 +++ b/sip-in/mncc_handle.c Sat Oct 08 13:28:30 2022 -0800 @@ -79,6 +79,30 @@ send_mncc_to_gsm(&msg, sizeof(struct gsm_mncc)); } +void +mncc_send_hold_ack(call) + struct call *call; +{ + struct gsm_mncc msg; + + bzero(&msg, sizeof(struct gsm_mncc)); + msg.msg_type = MNCC_HOLD_CNF; + msg.callref = call->mncc_callref; + send_mncc_to_gsm(&msg, sizeof(struct gsm_mncc)); +} + +void +mncc_send_retrieve_ack(call) + struct call *call; +{ + struct gsm_mncc msg; + + bzero(&msg, sizeof(struct gsm_mncc)); + msg.msg_type = MNCC_RETRIEVE_CNF; + msg.callref = call->mncc_callref; + send_mncc_to_gsm(&msg, sizeof(struct gsm_mncc)); +} + static void send_rtp_connect(call) struct call *call; @@ -205,11 +229,50 @@ struct call *call; struct gsm_mncc *msg; { - if (call->overall_state == OVERALL_STATE_CONNECTED && - call->mgw_state == MGW_STATE_COMPLETE) + if (call->overall_state != OVERALL_STATE_CONNECTED) + return; + if (call->mgw_state == MGW_STATE_COMPLETE) tmgw_send_dtmf_stop(call); - else + 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_gsm(msg, sizeof(struct gsm_mncc)); + } +} + +static void +handle_call_hold(call, msg) + struct call *call; + struct gsm_mncc *msg; +{ + if (call->overall_state != OVERALL_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_gsm(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->overall_state != OVERALL_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_gsm(msg, sizeof(struct gsm_mncc)); + return; + } + send_rtp_connect(call); + tmgw_send_mdcx_retrieve(call); } static void @@ -260,16 +323,10 @@ send_mncc_to_gsm(msg, sizeof(struct gsm_mncc)); return; case MNCC_HOLD_IND: - msg->msg_type = MNCC_HOLD_REJ; - mncc_set_cause(msg, GSM48_CAUSE_LOC_PRN_S_LU, - GSM48_CC_CAUSE_SERV_OPT_UNIMPL); - send_mncc_to_gsm(msg, sizeof(struct gsm_mncc)); + handle_call_hold(call, msg); return; case MNCC_RETRIEVE_IND: - msg->msg_type = MNCC_RETRIEVE_REJ; - mncc_set_cause(msg, GSM48_CAUSE_LOC_PRN_S_LU, - GSM48_CC_CAUSE_SERV_OPT_UNIMPL); - send_mncc_to_gsm(msg, sizeof(struct gsm_mncc)); + handle_call_retrieve(call, msg); return; } }