/* FUNCTIONS ******************************************************************/ void handle_isup_t35(void *userdata) { SS7_FUNC_TRACE_ENTER(__FUNCTION__); sngss7_timer_data_t *timer = userdata; sngss7_chan_data_t *sngss7_info = timer->sngss7_info; ftdm_channel_t *ftdmchan = sngss7_info->ftdmchan; /* now that we have the right channel...put a lock on it so no-one else can use it */ ftdm_mutex_lock(ftdmchan->mutex); SS7_ERROR("[Call-Control] Timer 35 expired on CIC = %d\n", sngss7_info->circuit->cic); /* set the flag to indicate this hangup is started from the local side */ sngss7_set_ckt_flag(sngss7_info, FLAG_LOCAL_REL); /* hang up on timer expiry */ ftdmchan->caller_data.hangup_cause = 28; /* end the call */ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_CANCEL); /*unlock*/ ftdm_mutex_unlock(ftdmchan->mutex); SS7_FUNC_TRACE_EXIT(__FUNCTION__); return; }
/* Unsed only for overlap receive */ void sngisdn_snd_setup_ack(ftdm_channel_t *ftdmchan) { CnStEvnt cnStEvnt; sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data; sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; if (!sngisdn_info->suInstId || !sngisdn_info->spInstId) { ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Sending SETUP ACK , but no call data, aborting (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId); sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_ABORT); ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); return; } memset(&cnStEvnt, 0, sizeof(cnStEvnt)); ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending SETUP ACK (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces); if(sng_isdn_con_status(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &cnStEvnt, MI_SETUPACK, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces)) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused SETUP ACK request\n"); } return; }
void sngisdn_snd_disconnect(ftdm_channel_t *ftdmchan) { DiscEvnt discEvnt; sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data; sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; if (!sngisdn_info->suInstId || !sngisdn_info->spInstId) { ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Sending DISCONNECT, but no call data, aborting (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId); sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_ABORT); ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE); return; } memset(&discEvnt, 0, sizeof(discEvnt)); set_cause_ie(ftdmchan, &discEvnt.causeDgn[0]); set_facility_ie(ftdmchan, &discEvnt.facilityStr); set_user_to_user_ie(ftdmchan, &discEvnt.usrUsr); ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending DISCONNECT (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId); if (sng_isdn_disc_request(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &discEvnt)) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused DISCONNECT request\n"); } return; }
void sngisdn_snd_connect(ftdm_channel_t *ftdmchan) { CnStEvnt cnStEvnt; sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data; sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; ftdm_sngisdn_progind_t prog_ind = {SNGISDN_PROGIND_LOC_USER, SNGISDN_PROGIND_DESCR_NETE_ISDN}; if (sngisdn_test_flag(sngisdn_info, FLAG_SENT_CONNECT)) { return; } sngisdn_set_flag(sngisdn_info, FLAG_SENT_CONNECT); if (!sngisdn_info->suInstId || !sngisdn_info->spInstId) { ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Sending CONNECT, but no call data, aborting (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId); sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_ABORT); ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); return; } memset(&cnStEvnt, 0, sizeof(cnStEvnt)); /* Indicate channel ID only in first response */ if (!ftdm_test_flag(sngisdn_info, FLAG_SENT_CHAN_ID)) { set_chan_id_ie(ftdmchan, &cnStEvnt.chanId); } set_prog_ind_ie(ftdmchan, &cnStEvnt.progInd, prog_ind); set_facility_ie(ftdmchan, &cnStEvnt.facilityStr); ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending CONNECT (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces); if (sng_isdn_con_response(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &cnStEvnt, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces)) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused CONNECT request\n"); } return; }
void sngisdn_snd_alert(ftdm_channel_t *ftdmchan, ftdm_sngisdn_progind_t prog_ind) { CnStEvnt cnStEvnt; sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data; sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; if (!sngisdn_info->suInstId || !sngisdn_info->spInstId) { ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Sending ALERT, but no call data, aborting (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId); sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_ABORT); ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); return; } memset(&cnStEvnt, 0, sizeof(cnStEvnt)); set_prog_ind_ie(ftdmchan, &cnStEvnt.progInd, prog_ind); set_facility_ie(ftdmchan, &cnStEvnt.facilityStr); ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending ALERT (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces); if(sng_isdn_con_status(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId,&cnStEvnt, MI_ALERTING, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces)) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused ALERT request\n"); } return; }
void sngisdn_snd_progress(ftdm_channel_t *ftdmchan, ftdm_sngisdn_progind_t prog_ind) { CnStEvnt cnStEvnt; sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data; sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; if (!sngisdn_info->suInstId || !sngisdn_info->spInstId) { ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Sending PROGRESS, but no call data, aborting (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId); sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_ABORT); ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); return; } if (signal_data->switchtype == SNGISDN_SWITCH_INSNET) { /* Trillium Q931 layer complains of invalid event when receiving PROGRESS in INSNET variant, so PROGRESS event is probably invalid */ return; } memset(&cnStEvnt, 0, sizeof(cnStEvnt)); set_prog_ind_ie(ftdmchan, &cnStEvnt.progInd, prog_ind); set_facility_ie(ftdmchan, &cnStEvnt.facilityStr); ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending PROGRESS (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces); if(sng_isdn_con_status(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId,&cnStEvnt, MI_PROGRESS, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces)) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused PROGRESS request\n"); } return; }
/* Used only for BRI PTMP - This function is used when the NT side makes a call out, and one or multiple TE's reply, then NT assigns the call by sending a con_complete*/ void sngisdn_snd_con_complete(ftdm_channel_t *ftdmchan) { CnStEvnt cnStEvnt; sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data; sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; if (!sngisdn_info->suInstId || !sngisdn_info->spInstId) { ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Sending CONNECT COMPL , but no call data, aborting (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId); sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_ABORT); ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); return; } memset(&cnStEvnt, 0, sizeof(cnStEvnt)); /* Indicate channel ID only in first response */ if (!ftdm_test_flag(sngisdn_info, FLAG_SENT_CHAN_ID)) { set_chan_id_ie(ftdmchan, &cnStEvnt.chanId); } ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending CONNECT COMPL (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces); if(sng_isdn_con_comp(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &cnStEvnt, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces)) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused CONNECT ACK request\n"); } return; }
void sngisdn_snd_release(ftdm_channel_t *ftdmchan, uint8_t glare) { RelEvnt relEvnt; uint32_t suInstId, spInstId; sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data; sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; if (!sngisdn_info->suInstId) { ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Sending RELEASE, but no call data, aborting (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId); sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_ABORT); ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE); return; } memset(&relEvnt, 0, sizeof(relEvnt)); /* Fill relEvnt here */ relEvnt.causeDgn[0].eh.pres = PRSNT_NODEF; relEvnt.causeDgn[0].location.pres = PRSNT_NODEF; relEvnt.causeDgn[0].location.val = IN_LOC_PRIVNETLU; relEvnt.causeDgn[0].codeStand3.pres = PRSNT_NODEF; relEvnt.causeDgn[0].codeStand3.val = IN_CSTD_CCITT; relEvnt.causeDgn[0].causeVal.pres = PRSNT_NODEF; relEvnt.causeDgn[0].causeVal.val = ftdmchan->caller_data.hangup_cause; relEvnt.causeDgn[0].recommend.pres = NOTPRSNT; relEvnt.causeDgn[0].dgnVal.pres = NOTPRSNT; if (glare) { suInstId = sngisdn_info->glare.suInstId; spInstId = sngisdn_info->glare.spInstId; } else { suInstId = sngisdn_info->suInstId; spInstId = sngisdn_info->spInstId; } set_facility_ie(ftdmchan, &relEvnt.facilityStr); ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending RELEASE/RELEASE COMPLETE (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, suInstId, spInstId); if (glare) { if (sng_isdn_release_request(signal_data->cc_id, suInstId, spInstId, &relEvnt)) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused RELEASE/RELEASE COMPLETE request\n"); } } else { if (sng_isdn_release_request(signal_data->cc_id, suInstId, spInstId, &relEvnt)) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused RELEASE/RELEASE COMPLETE request\n"); } } return; }
static void *test_call(ftdm_thread_t *me, void *obj) { ftdm_channel_t *chan = (ftdm_channel_t *) obj; uint8_t frame[1024]; ftdm_size_t len; char *number = strdup("5551212"); ftdm_sleep(10 * 1000); ftdm_log(FTDM_LOG_DEBUG, "answer call and start echo test\n"); ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_UP); ftdm_channel_command(chan, FTDM_COMMAND_SEND_DTMF, number); while (chan->state == FTDM_CHANNEL_STATE_UP) { ftdm_wait_flag_t flags = FTDM_READ; if (ftdm_channel_wait(chan, &flags, -1) == FTDM_FAIL) { break; } len = sizeof(frame); if (flags & FTDM_READ) { if (ftdm_channel_read(chan, frame, &len) == FTDM_SUCCESS) { //ftdm_log(FTDM_LOG_DEBUG, "WRITE %d\n", len); ftdm_channel_write(chan, frame, sizeof(frame), &len); } else { break; } } } if (chan->state == FTDM_CHANNEL_STATE_UP) { ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_BUSY); } ftdm_log(FTDM_LOG_DEBUG, "call over\n"); free(number); return NULL; }
static FIO_SIGNAL_CB_FUNCTION(on_signal) { ftdm_log(FTDM_LOG_DEBUG, "got sig [%s]\n", ftdm_signal_event2str(sigmsg->event_id)); switch(sigmsg->event_id) { case FTDM_SIGEVENT_START: ftdm_set_state_locked(sigmsg->channel, FTDM_CHANNEL_STATE_RING); ftdm_log(FTDM_LOG_DEBUG, "launching thread and indicating ring\n"); ftdm_thread_create_detached(test_call, sigmsg->channel); break; default: break; } return FTDM_SUCCESS; }
ftdm_status_t check_for_state_change(ftdm_channel_t *ftdmchan) { #if 0 ftdm_log_chan_msg(ftdmchan, "Checking for pending state change\n"); #endif /* check to see if there are any pending state changes on the channel and give them a sec to happen*/ ftdm_wait_for_flag_cleared(ftdmchan, FTDM_CHANNEL_STATE_CHANGE, 5000); /* check the flag to confirm it is clear now */ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) { /* the flag is still up...so we have a problem */ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "FTDM_CHANNEL_STATE_CHANGE set for over 500ms\n"); /* move the state of the channel to RESTART to force a reset */ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART); return FTDM_FAIL; } return FTDM_SUCCESS; }
static ftdm_status_t state_advance(ftdm_channel_t *ftdmchan) { ftdm_status_t status; ftdm_sigmsg_t sig; pritap_t *pritap = ftdmchan->span->signal_data; pritap_t *peer_pritap = pritap->peerspan->signal_data; ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "processing state %s\n", ftdm_channel_state2str(ftdmchan->state)); memset(&sig, 0, sizeof(sig)); sig.chan_id = ftdmchan->chan_id; sig.span_id = ftdmchan->span_id; sig.channel = ftdmchan; ftdm_channel_complete_state(ftdmchan); switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_DOWN: { ftdm_channel_t *fchan = ftdmchan; /* Destroy the peer data first */ if (fchan->call_data) { ftdm_channel_t *peerchan = fchan->call_data; ftdm_channel_t *pchan = peerchan; ftdm_channel_lock(peerchan); pchan->call_data = NULL; pchan->pflags = 0; ftdm_channel_close(&pchan); ftdm_channel_unlock(peerchan); } else { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "No call data?\n"); } ftdmchan->call_data = NULL; ftdmchan->pflags = 0; ftdm_channel_close(&fchan); } break; case FTDM_CHANNEL_STATE_PROGRESS: case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: case FTDM_CHANNEL_STATE_HANGUP: break; case FTDM_CHANNEL_STATE_UP: { if (ftdm_test_pflag(ftdmchan, PRITAP_NETWORK_ANSWER)) { ftdm_clear_pflag(ftdmchan, PRITAP_NETWORK_ANSWER); sig.event_id = FTDM_SIGEVENT_UP; ftdm_span_send_signal(ftdmchan->span, &sig); } } break; case FTDM_CHANNEL_STATE_RING: { sig.event_id = FTDM_SIGEVENT_START; /* The ring interface (where the setup was received) is the peer, since we RING the channel * where PROCEED/PROGRESS is received */ ftdm_sigmsg_add_var(&sig, "pritap_ring_interface", PRITAP_GET_INTERFACE(peer_pritap->iface)); if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) { ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); } } break; case FTDM_CHANNEL_STATE_TERMINATING: { if (ftdmchan->last_state != FTDM_CHANNEL_STATE_HANGUP) { sig.event_id = FTDM_SIGEVENT_STOP; status = ftdm_span_send_signal(ftdmchan->span, &sig); } ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); } break; default: { ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "ignoring state change from %s to %s\n", ftdm_channel_state2str(ftdmchan->last_state), ftdm_channel_state2str(ftdmchan->state)); } break; } return FTDM_SUCCESS; }