FreeCalypso > hg > themwi-system-sw
diff sip-out/call_setup.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/call_setup.c@1bbe57df74f6 |
children | e89619893c1e |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sip-out/call_setup.c Tue Oct 11 23:04:01 2022 -0800 @@ -0,0 +1,171 @@ +/* + * In this module we implement our initial handling of MNCC_SETUP_IND. + */ + +#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(); + +extern int block_1900_numbers; +extern struct call *call_list; + +static void +reject_mo_call(mncc, callref, cause_loc, cause_val) + struct mncc_conn *mncc; + uint32_t callref; +{ + struct gsm_mncc msg; + + bzero(&msg, sizeof(struct gsm_mncc)); + msg.msg_type = MNCC_REJ_REQ; + msg.callref = callref; + mncc_set_cause(&msg, cause_loc, cause_val); + send_mncc_to_sock(mncc, &msg, sizeof(struct gsm_mncc)); +} + +static void +send_call_proceeding(call) + struct call *call; +{ + struct gsm_mncc msg; + + bzero(&msg, sizeof(struct gsm_mncc)); + msg.msg_type = MNCC_CALL_PROC_REQ; + msg.callref = call->mncc_callref; + send_mncc_to_sock(call->mncc, &msg, sizeof(struct gsm_mncc)); +} + +void +handle_setup_ind(mncc, msg, msglen) + struct mncc_conn *mncc; + struct gsm_mncc *msg; + unsigned msglen; +{ + struct call *call; + struct sip_out_dest *dest; + struct special_num_route *special_rt; + char to_sip_user[MAX_SIP_USER_PART+1]; + int rc; + + if (msglen != sizeof(struct gsm_mncc)) { + syslog(LOG_CRIT, + "FATAL: Rx MNCC_SETUP_IND has wrong length"); + exit(1); + } + /* check for duplicates */ + call = find_call_by_mncc_callref(mncc, msg->callref); + if (call) { + syslog(LOG_ERR, "duplicate MNCC_SETUP_IND for callref 0x%x", + msg->callref); + /* drop it like OsmoMSC's mncc_builtin does */ + return; + } + if (!(msg->fields & MNCC_F_CALLED) || + !(msg->fields & MNCC_F_BEARER_CAP)) { + syslog(LOG_ERR, "rejecting MO call 0x%x: missing mandatory IE", + msg->callref); + reject_mo_call(mncc, msg->callref, GSM48_CAUSE_LOC_PRN_S_LU, + GSM48_CC_CAUSE_INVAL_MAND_INF); + return; + } + /* route based on destination address */ + refresh_out_routes_db(); + if (msg->called.type == GSM48_TON_INTERNATIONAL) { + rc = grok_number_string(msg->called.number, 0); + if (rc < 2 || rc > MAX_E164_NUMBER) { +inv_nr_format: reject_mo_call(mncc, msg->callref, + GSM48_CAUSE_LOC_PRN_S_LU, + GSM48_CC_CAUSE_INV_NR_FORMAT); + return; + } + if (msg->called.number[0] == '0') + goto inv_nr_format; + if (msg->called.number[0] == '1') { + if (rc != 11) + goto inv_nr_format; + if (!is_nanp_valid_prefix(msg->called.number+1)) + goto inv_nr_format; + if (msg->called.number[1] == '9' && + msg->called.number[2] == '0' && + msg->called.number[3] == '0' && + block_1900_numbers) { +call_barred: reject_mo_call(mncc, msg->callref, + GSM48_CAUSE_LOC_PRN_S_LU, + GSM48_CC_CAUSE_OP_DET_BARRING); + return; + } + } + rc = route_e164_number(msg->called.number, &dest); + if (!rc) { +no_route_to_dest: reject_mo_call(mncc, msg->callref, + GSM48_CAUSE_LOC_PRN_S_LU, + GSM48_CC_CAUSE_NO_ROUTE); + return; + } + to_sip_user[0] = '+'; + strcpy(to_sip_user+1, msg->called.number); + } else { + rc = route_special_number(msg->called.number, &dest, + &special_rt); + if (!rc) + goto no_route_to_dest; + strcpy(to_sip_user, special_rt->sip_user); + } + /* validate From number */ + if (!(msg->fields & MNCC_F_CALLING)) + goto call_barred; + if (msg->calling.type != GSM48_TON_INTERNATIONAL) + goto call_barred; + if (grok_number_string(msg->calling.number, 0) != 11 || + msg->calling.number[0] != '1') + goto call_barred; + /* speech-only restriction */ + if (msg->bearer_cap.transfer != GSM48_BCAP_ITCAP_SPEECH || + msg->bearer_cap.mode != GSM48_BCAP_TMOD_CIRCUIT) { + syslog(LOG_ERR, "rejecting MO call 0x%x: bad bearer cap", + msg->callref); + reject_mo_call(mncc, msg->callref, GSM48_CAUSE_LOC_PRN_S_LU, + GSM48_CC_CAUSE_BEARER_CA_UNAVAIL); + return; + } + /* TMGW must be up and running */ + rc = connect_tmgw_socket(); + if (rc < 0) { + reject_mo_call(mncc, msg->callref, GSM48_CAUSE_LOC_PRN_S_LU, + GSM48_CC_CAUSE_NETWORK_OOO); + return; + } + /* allocate struct call and being stateful processing */ + call = malloc(sizeof(struct call)); + if (!call) { + syslog(LOG_CRIT, "failed malloc for outbound call!"); + reject_mo_call(mncc, msg->callref, GSM48_CAUSE_LOC_PRN_S_LU, + GSM48_CC_CAUSE_RESOURCE_UNAVAIL); + return; + } + bzero(call, sizeof(struct call)); + call->mncc = mncc; + call->mncc_callref = msg->callref; + call->from_user[0] = '+'; + strcpy(call->from_user+1, msg->calling.number); + sprintf(call->to_uri, "sip:%s@%s", to_sip_user, dest->domain); + bcopy(&dest->sin, &call->udp_sin, sizeof(struct sockaddr_in)); + call->next = call_list; + call_list = call; + send_call_proceeding(call); + call->overall_state = OVERALL_STATE_GSM_RTP; + call->mncc_state = MNCC_STATE_MO_PROC; +}