FreeCalypso > hg > themwi-system-sw
view sip-in/mncc_handle.c @ 112:6aa63cf4620a
sip-in call clearing: select timeout implemented
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Wed, 28 Sep 2022 18:59:55 -0800 |
parents | c1c94b7fc2e2 |
children | 5685412bd6aa |
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 "call.h" extern struct call *find_call_by_mncc_callref(); static struct gsm_mncc_cause default_cause = { .coding = GSM48_CAUSE_CODING_GSM, .location = GSM48_CAUSE_LOC_PRN_S_LU, .value = GSM48_CC_CAUSE_NORMAL_UNSPEC, }; void send_mncc_connect_ack(call) struct call *call; { struct gsm_mncc ack; bzero(&ack, sizeof(struct gsm_mncc)); ack.msg_type = MNCC_SETUP_COMPL_REQ; ack.callref = call->mncc_callref; send_mncc_to_gsm(&ack, sizeof(struct gsm_mncc)); call->mncc_state = MNCC_STATE_CONNECTED; call->overall_state = OVERALL_STATE_CONNECTED; } static void handle_alerting(call, msg) struct call *call; struct gsm_mncc *msg; { if (call->mncc_state != MNCC_STATE_STARTED) { syslog(LOG_ERR, "MNCC_ALERT_IND in wrong MNCC state 0x%x", call->mncc_state); return; } call->mncc_state = MNCC_STATE_ALERTING; call->overall_state = OVERALL_STATE_ALERTING; signal_invite_ringing(call); } static void handle_answer(call, msg) struct call *call; struct gsm_mncc *msg; { if (call->mncc_state != MNCC_STATE_STARTED && call->mncc_state != MNCC_STATE_ALERTING) { syslog(LOG_ERR, "MNCC_SETUP_CNF in wrong MNCC state 0x%x", call->mncc_state); return; } call->mncc_state = MNCC_STATE_ANSWERED; call->overall_state = OVERALL_STATE_ANSWERED; /* right now we require MNCC_RTP_CREATE to have come first */ if (!call->gsm_payload_msg_type) { call->overall_state = OVERALL_STATE_TEARDOWN; disconnect_mncc(call, GSM48_CAUSE_LOC_PRN_S_LU, GSM48_CC_CAUSE_PROTO_ERR); disconnect_tmgw(call); strcpy(call->invite_fail, "502 Internal protocol error"); signal_invite_error(call); return; } tmgw_send_mdcx_connect(call); } static void handle_disconnect_ind(call, msg) struct call *call; struct gsm_mncc *msg; { struct gsm_mncc_cause *cause; /* release back to MNCC */ msg->msg_type = MNCC_REL_REQ; send_mncc_to_gsm(msg, sizeof(struct gsm_mncc)); call->mncc_state = MNCC_STATE_RELEASE; /* signal disconnect to SIP */ call->overall_state = OVERALL_STATE_TEARDOWN; if (msg->fields & MNCC_F_CAUSE) cause = &msg->cause; else cause = &default_cause; disconnect_sip(call, cause); disconnect_tmgw(call); } static void handle_final_release(call, msg) struct call *call; struct gsm_mncc *msg; { struct gsm_mncc_cause *cause; /* MNCC call leg is gone */ call->mncc_state = MNCC_STATE_NO_EXIST; /* signal disconnect to SIP */ call->overall_state = OVERALL_STATE_TEARDOWN; if (msg->fields & MNCC_F_CAUSE) cause = &msg->cause; else cause = &default_cause; disconnect_sip(call, cause); disconnect_tmgw(call); transition_dead_sip(call); } static void handle_signaling_msg(msg, msglen) 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(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_SETUP_CNF: handle_answer(call, msg); return; case MNCC_ALERT_IND: handle_alerting(call, msg); return; case MNCC_DISC_IND: handle_disconnect_ind(call, msg); return; case MNCC_REL_IND: case MNCC_REL_CNF: case MNCC_REJ_IND: handle_final_release(call, msg); return; case MNCC_START_DTMF_IND: msg->msg_type = MNCC_START_DTMF_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)); return; case MNCC_STOP_DTMF_IND: msg->msg_type = MNCC_STOP_DTMF_RSP; send_mncc_to_gsm(msg, sizeof(struct gsm_mncc)); 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_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)); 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)); return; } } static void handle_rtp_create(msg, msglen) 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(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); } /* 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; /* respond with MNCC_RTP_CONNECT */ msg->msg_type = MNCC_RTP_CONNECT; bcopy(&call->gsm_rtp_tmgw, &msg->addr, sizeof(struct sockaddr_storage)); send_mncc_to_gsm(msg, sizeof(struct gsm_mncc_rtp)); } void msg_from_mncc(msg, msglen) union mncc_msg *msg; unsigned msglen; { switch (msg->msg_type) { case MNCC_SETUP_CNF: case MNCC_CALL_CONF_IND: case MNCC_ALERT_IND: case MNCC_NOTIFY_IND: case MNCC_DISC_IND: case MNCC_FACILITY_IND: case MNCC_START_DTMF_IND: case MNCC_STOP_DTMF_IND: case MNCC_MODIFY_IND: case MNCC_HOLD_IND: case MNCC_RETRIEVE_IND: case MNCC_USERINFO_IND: case MNCC_REL_IND: case MNCC_REL_CNF: case MNCC_REJ_IND: handle_signaling_msg(msg, msglen); return; case MNCC_RTP_CREATE: handle_rtp_create(msg, msglen); return; case MNCC_RTP_CONNECT: syslog(LOG_ERR, "MNCC_RTP_CONNECT error from OsmoMSC"); return; case MNCC_RTP_FREE: syslog(LOG_ERR, "MNCC_RTP_FREE bogon from OsmoMSC"); return; default: syslog(LOG_CRIT, "FATAL: received unexpected MNCC message type 0x%x", msg->msg_type); exit(1); } }