FreeCalypso > hg > themwi-system-sw
diff sip-out/mncc_sig_in.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/mncc_handle.c@99fd4ae573ae |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sip-out/mncc_sig_in.c Tue Oct 11 23:04:01 2022 -0800 @@ -0,0 +1,214 @@ +/* + * In this module we implement our handling of call control messages + * from OsmoMSC relayed to us via themwi-mncc. + */ + +#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(); + +static void +handle_disconnect_ind(call, msg) + struct call *call; + struct gsm_mncc *msg; +{ + /* release back to MNCC */ + msg->msg_type = MNCC_REL_REQ; + send_mncc_to_sock(call->mncc, msg, sizeof(struct gsm_mncc)); + call->mncc_state = MNCC_STATE_RELEASE; + /* signal disconnect to SIP */ + call->overall_state = OVERALL_STATE_TEARDOWN; + disconnect_sip(call); + disconnect_tmgw(call); +} + +static void +handle_final_release(call, msg) + struct call *call; + struct gsm_mncc *msg; +{ + /* MNCC call leg is gone */ + call->mncc = 0; + /* signal disconnect to SIP */ + call->overall_state = OVERALL_STATE_TEARDOWN; + disconnect_sip(call); + disconnect_tmgw(call); + check_dead_call(call); +} + +static void +handle_dtmf_start(call, msg) + struct call *call; + struct gsm_mncc *msg; +{ + if (!(msg->fields & MNCC_F_KEYPAD) || + !is_valid_dtmf_digit(msg->keypad)) { + msg->msg_type = MNCC_START_DTMF_REJ; + mncc_set_cause(msg, GSM48_CAUSE_LOC_PRN_S_LU, + GSM48_CC_CAUSE_INVAL_MAND_INF); + send_mncc_to_sock(call->mncc, msg, sizeof(struct gsm_mncc)); + return; + } + if (call->mncc_state != MNCC_STATE_CONNECTED || + call->mgw_state != MGW_STATE_COMPLETE) { + msg->msg_type = MNCC_START_DTMF_REJ; + mncc_set_cause(msg, GSM48_CAUSE_LOC_PRN_S_LU, + GSM48_CC_CAUSE_MSGTYPE_INCOMPAT); + send_mncc_to_sock(call->mncc, msg, sizeof(struct gsm_mncc)); + return; + } + call->dtmf_digit = msg->keypad; + tmgw_send_dtmf_start(call); +} + +static void +handle_dtmf_stop(call, msg) + struct call *call; + struct gsm_mncc *msg; +{ + if (call->mncc_state != MNCC_STATE_CONNECTED) + return; + if (call->mgw_state == MGW_STATE_COMPLETE) + tmgw_send_dtmf_stop(call); + 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_sock(call->mncc, msg, sizeof(struct gsm_mncc)); + } +} + +static void +handle_call_hold(call, msg) + struct call *call; + struct gsm_mncc *msg; +{ + if (call->mncc_state != MNCC_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_sock(call->mncc, 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->mncc_state != MNCC_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_sock(call->mncc, msg, sizeof(struct gsm_mncc)); + return; + } + send_rtp_connect(call); + tmgw_send_mdcx_retrieve(call); +} + +void +handle_mncc_signal(mncc, msg, msglen) + struct mncc_conn *mncc; + struct gsm_mncc *msg; + unsigned msglen; +{ + struct call *call; + + if (msglen != sizeof(struct gsm_mncc)) { + syslog(LOG_CRIT, + "FATAL: Rx MNCC message type 0x%x has wrong length", + msg->msg_type); + exit(1); + } + call = find_call_by_mncc_callref(mncc, msg->callref); + if (!call) { + syslog(LOG_CRIT, + "error: Rx MNCC message type 0x%x has invalid callref 0x%x", + msg->msg_type, msg->callref); + exit(1); + } + switch (msg->msg_type) { + case MNCC_DISC_IND: + handle_disconnect_ind(call, msg); + return; + case MNCC_REL_IND: + case MNCC_REL_CNF: + handle_final_release(call, msg); + return; + case MNCC_START_DTMF_IND: + handle_dtmf_start(call, msg); + return; + case MNCC_STOP_DTMF_IND: + handle_dtmf_stop(call, msg); + return; + case MNCC_MODIFY_IND: + msg->msg_type = MNCC_MODIFY_REJ; + mncc_set_cause(msg, GSM48_CAUSE_LOC_PRN_S_LU, + GSM48_CC_CAUSE_SERV_OPT_UNIMPL); + send_mncc_to_sock(mncc, msg, sizeof(struct gsm_mncc)); + return; + case MNCC_HOLD_IND: + handle_call_hold(call, msg); + return; + case MNCC_RETRIEVE_IND: + handle_call_retrieve(call, msg); + return; + } +} + +void +handle_rtp_create(mncc, msg, msglen) + struct mncc_conn *mncc; + struct gsm_mncc_rtp *msg; + unsigned msglen; +{ + struct call *call; + + if (msglen != sizeof(struct gsm_mncc_rtp)) { + syslog(LOG_CRIT, + "FATAL: Rx MNCC message type 0x%x has wrong length", + msg->msg_type); + exit(1); + } + call = find_call_by_mncc_callref(mncc, msg->callref); + if (!call) { + syslog(LOG_CRIT, + "error: Rx MNCC message type 0x%x has invalid callref 0x%x", + msg->msg_type, msg->callref); + exit(1); + } + /* we need to be in the right state */ + if (call->mncc_state != MNCC_STATE_MO_PROC) { + syslog(LOG_ERR, + "duplicate MNCC_RTP_CREATE for MO callref 0x%x, ignoring", + msg->callref); + return; + } + /* save Osmocom network RTP information */ + bcopy(&msg->addr, &call->gsm_rtp_osmo, sizeof(struct sockaddr_storage)); + call->gsm_payload_type = msg->payload_type; + call->gsm_payload_msg_type = msg->payload_msg_type; + /* move forward */ + call->mncc_state = MNCC_STATE_GOT_RTP; + call->overall_state = OVERALL_STATE_CRCX; + tmgw_send_crcx(call); +}