FreeCalypso > hg > themwi-system-sw
view sip-out/mncc_sig_in.c @ 198:cf1ba5d65188
mgw: start using project-global rtp_defs.h
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Wed, 29 Mar 2023 20:06:40 -0800 |
parents | e54b0a9e322f |
children |
line wrap: on
line source
/* * 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); }