FreeCalypso > hg > themwi-system-sw
view sip-out/call_setup.c @ 267:81958b35f74d
NANP validation: allow made-up area codes of N9X form
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Mon, 13 Nov 2023 15:28:09 -0800 |
parents | 556cd78f750a |
children |
line wrap: on
line source
/* * 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, prefix_len; 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 < 7 || 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, &prefix_len); if (!rc) { no_route_to_dest: reject_mo_call(mncc, msg->callref, GSM48_CAUSE_LOC_PRN_S_LU, GSM48_CC_CAUSE_NO_ROUTE); return; } /* made-up N9X area codes require explicit routes */ if (msg->called.number[0] == '1' && msg->called.number[2] == '9' && prefix_len < 4) goto no_route_to_dest; to_sip_user[0] = '+'; strcpy(to_sip_user+1, msg->called.number); special_rt = 0; } 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; } /* E911 special handling */ if (special_rt && special_rt->flags & SPECIAL_NUM_FLAG_E911) { rc = e911_call_preen(msg); if (!rc) goto call_barred; } /* 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; syslog(LOG_INFO, "Outbound call from %s to %s", call->from_user, call->to_uri); }