/* The stacks is wants to transmit a frame */ int16_t sngisdn_rcv_l1_data_req(uint16_t spId, sng_l1_frame_t *l1_frame) { ftdm_status_t status; ftdm_wait_flag_t flags = FTDM_WRITE; sngisdn_span_data_t *signal_data = g_sngisdn_data.dchans[spId].spans[1]; ftdm_size_t length = l1_frame->len; ftdm_assert(signal_data, "Received Data request on unconfigured span\n"); do { flags = FTDM_WRITE; status = signal_data->dchan->fio->wait(signal_data->dchan, &flags, 1000); if (status != FTDM_SUCCESS) { ftdm_log_chan_msg(signal_data->dchan, FTDM_LOG_WARNING, "transmit timed-out\n"); return -1; } if ((flags & FTDM_WRITE)) { status = signal_data->dchan->fio->write(signal_data->dchan, l1_frame->data, (ftdm_size_t*)&length); if (status != FTDM_SUCCESS) { ftdm_log_chan_msg(signal_data->dchan, FTDM_LOG_CRIT, "Failed to transmit frame\n"); return -1; } break; /* On WIN32, it is possible for poll to return without FTDM_WRITE flag set, so we try to retransmit */ #ifndef WIN32 } else { ftdm_log_chan_msg(signal_data->dchan, FTDM_LOG_WARNING, "Failed to poll for d-channel\n"); return -1; #endif } } while(1); return 0; }
void sngisdn_process_disc_ind (sngisdn_event_data_t *sngisdn_event) { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); int16_t suId = sngisdn_event->suId; uint32_t suInstId = sngisdn_event->suInstId; uint32_t spInstId = sngisdn_event->spInstId; sngisdn_chan_data_t *sngisdn_info = sngisdn_event->sngisdn_info; ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan; DiscEvnt *discEvnt = &sngisdn_event->event.discEvnt; ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Processing DISCONNECT (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); ftdm_assert(!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE), "State change flag pending\n"); switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_RING: case FTDM_CHANNEL_STATE_DIALING: case FTDM_CHANNEL_STATE_PROGRESS: case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: case FTDM_CHANNEL_STATE_UP: if (discEvnt->causeDgn[0].eh.pres && discEvnt->causeDgn[0].causeVal.pres) { ftdmchan->caller_data.hangup_cause = discEvnt->causeDgn[0].causeVal.val; } else { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "DISCONNECT did not have a cause code\n"); ftdmchan->caller_data.hangup_cause = 0; } sngisdn_set_flag(sngisdn_info, FLAG_REMOTE_REL); ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); break; case FTDM_CHANNEL_STATE_COLLECT: case FTDM_CHANNEL_STATE_GET_CALLERID: ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_CANCEL); break; case FTDM_CHANNEL_STATE_DOWN: /* somehow we are in down, nothing we can do locally */ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Received DISCONNECT but we are in DOWN state\n"); break; case FTDM_CHANNEL_STATE_HANGUP_COMPLETE: /* This is a race condition. We just sent a DISCONNECT, on this channel */ /* Do nothing */ break; default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Received DISCONNECT in an invalid state (%s)\n", ftdm_channel_state2str(ftdmchan->state)); /* start reset procedure */ /* Start the release procedure */ ftdm_set_flag(sngisdn_info, FLAG_REMOTE_REL); ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); break; } ISDN_FUNC_TRACE_EXIT(__FUNCTION__); return; }
/* The stacks is wants to transmit a frame */ int16_t sngisdn_rcv_l1_data_req(uint16_t spId, sng_l1_frame_t *l1_frame) { ftdm_status_t status; ftdm_wait_flag_t flags = FTDM_WRITE; sngisdn_span_data_t *signal_data = g_sngisdn_data.dchans[spId].spans[1]; ftdm_size_t length = l1_frame->len; ftdm_assert(signal_data, "Received Data request on unconfigured span\n"); do { flags = FTDM_WRITE; status = signal_data->dchan->fio->wait(signal_data->dchan, &flags, 1000); switch(status) { case FTDM_SUCCESS: break; case FTDM_TIMEOUT: continue; case FTDM_FAIL: default: ftdm_log_chan_msg(signal_data->dchan, FTDM_LOG_WARNING, "failed to poll for channel\n"); return -1; } /* status = FTDM_SUCCESS */ if ((flags & FTDM_WRITE)) { #if 0 int i; char string [2000]; unsigned string_len = 0; for (i = 0; i < length; i++) { string_len += sprintf(&string[string_len], "0x%02x ", l1_frame->data[i]); } ftdm_log_chan(signal_data->dchan, FTDM_LOG_CRIT, "\nL1 TX [%s]\n", string); #endif status = signal_data->dchan->fio->write(signal_data->dchan, l1_frame->data, (ftdm_size_t*)&length); if (status != FTDM_SUCCESS) { ftdm_log_chan_msg(signal_data->dchan, FTDM_LOG_CRIT, "Failed to transmit frame\n"); return -1; } break; /* On WIN32, it is possible for poll to return without FTDM_WRITE flag set, so we try to retransmit */ #ifndef WIN32 } else { ftdm_log_chan_msg(signal_data->dchan, FTDM_LOG_WARNING, "Failed to poll for d-channel\n"); return -1; #endif } } while(1); return 0; }
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; }
void sngisdn_process_fac_ind (sngisdn_event_data_t *sngisdn_event) { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); int16_t suId = sngisdn_event->suId; uint32_t suInstId = sngisdn_event->suInstId; uint32_t spInstId = sngisdn_event->spInstId; sngisdn_chan_data_t *sngisdn_info = sngisdn_event->sngisdn_info; ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan; sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; FacEvnt *facEvnt = &sngisdn_event->event.facEvnt; ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Processing FACILITY IND (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_GET_CALLERID: /* Update the caller ID Name */ if (facEvnt->facElmt.facStr.pres) { char retrieved_str[255]; /* return values for "sng_isdn_retrieve_facility_information_following": If there will be no information following, or fails to decode IE, returns -1 If there will be no information following, but current FACILITY IE contains a caller name, returns 0 If there will be information following, returns 1 */ if (sng_isdn_retrieve_facility_caller_name(&facEvnt->facElmt.facStr.val[2], facEvnt->facElmt.facStr.len, retrieved_str) == 0) { strcpy(ftdmchan->caller_data.cid_name, retrieved_str); } else { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Failed to retrieve Caller Name from Facility IE\n"); } if (signal_data->facility_timeout) { /* Cancel facility timeout */ ftdm_sched_cancel_timer(signal_data->sched, sngisdn_info->timers[SNGISDN_TIMER_FACILITY]); } } ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); break; case FTDM_CHANNEL_STATE_RING: /* We received the caller ID Name in FACILITY, but its too late, facility-timeout already occurred */ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "FACILITY received, but we already proceeded with call\n"); break; default: /* We do not support other FACILITY types for now, so do nothing */ break; } ISDN_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; }
/** * \brief Reads data from a Wanpipe channel * \param ftdmchan Channel to read from * \param data Data buffer * \param datalen Size of data buffer * \return Success, failure or timeout */ static FIO_READ_FUNCTION(wanpipe_read) { int rx_len = 0; int myerrno = 0; wp_tdm_api_rx_hdr_t hdrframe; memset(&hdrframe, 0, sizeof(hdrframe)); rx_len = sangoma_readmsg_tdm(ftdmchan->sockfd, &hdrframe, (int)sizeof(hdrframe), data, (int)*datalen, 0); *datalen = rx_len; if (rx_len == 0) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Read 0 bytes\n"); return FTDM_TIMEOUT; } if (rx_len < 0) { myerrno = errno; snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno)); ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Failed to read from sangoma device: %s (%d)\n", strerror(errno), rx_len); return FTDM_FAIL; } return FTDM_SUCCESS; }
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; }
/** * \brief Destroys a Wanpipe Channel * \param ftdmchan Channel to destroy * \return Success */ static FIO_CHANNEL_DESTROY_FUNCTION(wanpipe_channel_destroy) { #ifdef LIBSANGOMA_VERSION if (ftdmchan->mod_data) { sangoma_wait_obj_t *sangoma_wait_obj; sangoma_wait_obj = ftdmchan->mod_data; ftdmchan->mod_data = NULL; sangoma_wait_obj_delete(&sangoma_wait_obj); } #endif if (ftdmchan->sockfd != FTDM_INVALID_SOCKET) { /* enable HW DTMF. As odd as it seems. Why enable when the channel is being destroyed and won't be used anymore? * because that way we can transfer the DTMF state back to the driver, if we're being restarted we will set again * the FEATURE_DTMF flag and use HW DTMF, if we don't enable here, then on module restart we won't see * HW DTMF available and will use software */ if (ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_DTMF_DETECT)) { wanpipe_tdm_api_t tdm_api; int err; memset(&tdm_api, 0, sizeof(tdm_api)); err = sangoma_tdm_enable_dtmf_events(ftdmchan->sockfd, &tdm_api); if (err) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Failed enabling Sangoma HW DTMF failed on channel destroy\n"); } } sangoma_close(&ftdmchan->sockfd); } return FTDM_SUCCESS; }
void sngisdn_snd_fac_req(ftdm_channel_t *ftdmchan) { FacEvnt facEvnt; 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 FACILITY, but no call data, ignoring (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId); return; } memset(&facEvnt, 0, sizeof(facEvnt)); if (set_facility_ie_str(ftdmchan, &facEvnt.facElmt.facStr.val[2], (uint8_t*)&facEvnt.facElmt.facStr.len) != FTDM_SUCCESS) { /* No point in sending a FACILITY message if there is no Facility IE to transmit */ return; } facEvnt.facElmt.eh.pres = PRSNT_NODEF; facEvnt.facElmt.facStr.pres = PRSNT_NODEF; facEvnt.facElmt.facStr.val[0] = 0x1C; facEvnt.facElmt.facStr.val[1] = (uint8_t)facEvnt.facElmt.facStr.len; facEvnt.facElmt.facStr.len +=2; /* Need to include the size of identifier + len */ ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending FACILITY (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_facility_request(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &facEvnt, MI_FACIL, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces)) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused FACILITY 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; }
ftdm_status_t set_bear_cap_ie(ftdm_channel_t *ftdmchan, BearCap *bearCap) { sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; bearCap->eh.pres = PRSNT_NODEF; bearCap->infoTranCap.pres = PRSNT_NODEF; bearCap->infoTranCap.val = sngisdn_get_infoTranCap_from_user(ftdmchan->caller_data.bearer_capability); bearCap->codeStand0.pres = PRSNT_NODEF; bearCap->codeStand0.val = IN_CSTD_CCITT; bearCap->infoTranRate0.pres = PRSNT_NODEF; bearCap->infoTranRate0.val = IN_ITR_64KBIT; bearCap->tranMode.pres = PRSNT_NODEF; bearCap->tranMode.val = IN_TM_CIRCUIT; bearCap->usrInfoLyr1Prot.pres = PRSNT_NODEF; bearCap->usrInfoLyr1Prot.val = sngisdn_get_usrInfoLyr1Prot_from_user(ftdmchan->caller_data.bearer_layer1); switch (signal_data->switchtype) { case SNGISDN_SWITCH_NI2: case SNGISDN_SWITCH_4ESS: case SNGISDN_SWITCH_5ESS: case SNGISDN_SWITCH_DMS100: case SNGISDN_SWITCH_INSNET: if (bearCap->usrInfoLyr1Prot.val == IN_UIL1_G711ALAW) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Overriding bearer cap to u-law\n"); bearCap->usrInfoLyr1Prot.val = IN_UIL1_G711ULAW; } break; case SNGISDN_SWITCH_EUROISDN: case SNGISDN_SWITCH_QSIG: if (bearCap->usrInfoLyr1Prot.val == IN_UIL1_G711ULAW) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Overriding bearer cap to a-law\n"); bearCap->usrInfoLyr1Prot.val = IN_UIL1_G711ALAW; } break; } bearCap->lyr1Ident.pres = PRSNT_NODEF; bearCap->lyr1Ident.val = IN_L1_IDENT; return FTDM_SUCCESS; }
ftdm_status_t sngisdn_transfer(ftdm_channel_t *ftdmchan) { const char* args; char *p; char *type = NULL; char *target = NULL; ftdm_status_t status = FTDM_FAIL; sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data; unsigned i; args = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "transfer_arg"); if (ftdm_strlen_zero(args)) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Cannot perform transfer because call_transfer_arg variable is not set\n"); goto done; } type = ftdm_strdup(args); if ((p = strchr(type, '/'))) { target = ftdm_strdup(p+1); *p = '\0'; } if (ftdm_strlen_zero(type) || ftdm_strlen_zero(target)) { ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Invalid parameters for transfer %s, expected <type>/<target>\n", args); goto done; } if (sngisdn_info->transfer_data.type != SNGISDN_TRANSFER_NONE) { ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Cannot perform transfer because an existing transfer transfer is pending (%s)\n", sngisdn_transfer_type2str(sngisdn_info->transfer_data.type)); goto done; } ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Transfer requested type:%s target:%s\n", type, target); for (i = 0; i < ftdm_array_len(transfer_interfaces); i++ ) { if (!strcasecmp(transfer_interfaces[i].name, type)) { /* Depending on the transfer type, the transfer function may change the * channel state to UP, or last_state, but the transfer function will always result in * an immediate state change if FTDM_SUCCESS is returned */ status = transfer_interfaces[i].func(ftdmchan, transfer_interfaces[i].type, target); goto done; } } ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Invalid transfer type:%s\n", type); done: if (status != FTDM_SUCCESS) { ftdm_set_state(ftdmchan, ftdmchan->last_state); } ftdm_safe_free(type); ftdm_safe_free(target); return status; }
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; }
void sngisdn_snd_setup(ftdm_channel_t *ftdmchan) { ConEvnt conEvnt; sngisdn_chan_data_t *sngisdn_info = 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_INVALID}; ftdm_assert((!sngisdn_info->suInstId && !sngisdn_info->spInstId), "Trying to call out, but call data was not cleared\n"); sngisdn_info->suInstId = get_unique_suInstId(signal_data->cc_id); sngisdn_info->spInstId = 0; ftdm_mutex_lock(g_sngisdn_data.ccs[signal_data->cc_id].mutex); g_sngisdn_data.ccs[signal_data->cc_id].active_suInstIds[sngisdn_info->suInstId] = sngisdn_info; ftdm_mutex_unlock(g_sngisdn_data.ccs[signal_data->cc_id].mutex); memset(&conEvnt, 0, sizeof(conEvnt)); if (signal_data->switchtype == SNGISDN_SWITCH_EUROISDN || signal_data->force_sending_complete == SNGISDN_OPT_TRUE) { conEvnt.sndCmplt.eh.pres = PRSNT_NODEF; } if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP && signal_data->signalling == SNGISDN_SIGNALING_NET) { sngisdn_info->ces = CES_MNGMNT; } ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Outgoing call: Called No:[%s] Calling No:[%s]\n", ftdmchan->caller_data.dnis.digits, ftdmchan->caller_data.cid_num.digits); set_chan_id_ie(ftdmchan, &conEvnt.chanId); set_bear_cap_ie(ftdmchan, &conEvnt.bearCap[0]); set_called_num(ftdmchan, &conEvnt.cdPtyNmb); set_calling_num(ftdmchan, &conEvnt.cgPtyNmb); set_calling_num2(ftdmchan, &conEvnt.cgPtyNmb2); set_calling_subaddr(ftdmchan, &conEvnt.cgPtySad); set_called_subaddr(ftdmchan, &conEvnt.cdPtySad); set_redir_num(ftdmchan, &conEvnt.redirNmb); set_calling_name(ftdmchan, &conEvnt); set_network_specific_fac(ftdmchan, &conEvnt.netFac[0]); /* set_facility_ie will overwrite Calling Name for NI-2 if user specifies custom Facility IE */ set_facility_ie(ftdmchan, &conEvnt.facilityStr); set_prog_ind_ie(ftdmchan, &conEvnt.progInd, prog_ind); ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending SETUP (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_request(signal_data->cc_id, sngisdn_info->suInstId, &conEvnt, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces)) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused SETUP request\n"); } return; }
/* This is used to request Q.921 to initiate link establishment */ void sngisdn_snd_dl_req(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; memset(&cnStEvnt, 0, sizeof(cnStEvnt)); ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Requesting Link establishment (suId:%d dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces); if (sng_isdn_con_status(signal_data->cc_id, 0, 0, &cnStEvnt, MI_INFO, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces)) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused Link establishment\n"); } return; }
void sngisdn_snd_status_enq(ftdm_channel_t *ftdmchan) { StaEvnt staEvnt; 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_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Sending STATUS ENQ\n"); memset(&staEvnt, 0, sizeof(StaEvnt)); ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending Status ENQ on suId:%d suInstId:%u spInstId:%d 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_status_request(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &staEvnt, MI_STATENQ)) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused Status ENQ request\n"); } return; }
void sngisdn_snd_restart(ftdm_channel_t *ftdmchan) { Rst rstEvnt; sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; memset(&rstEvnt, 0, sizeof(rstEvnt)); set_chan_id_ie(ftdmchan, &rstEvnt.chanId); set_restart_ind_ie(ftdmchan, &rstEvnt.rstInd); ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending RESTART (suId:%d dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_dchan(signal_data)->link_id, CES_MNGMNT); if (sng_isdn_restart_request(signal_data->cc_id, &rstEvnt, sngisdn_dchan(signal_data)->link_id, CES_MNGMNT, IN_SND_RST)) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused RESTART request\n"); } return; }
/* French SPIROU send Charging Acknowledgement */ void ft_to_sngss7_txa (ftdm_channel_t * ftdmchan) { #ifndef SANGOMA_SPIROU SS7_FUNC_TRACE_ENTER (__FUNCTION__); ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "TXA message not supported!, please update your libsng_ss7\n"); #else SiCnStEvnt txa; sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; SS7_FUNC_TRACE_ENTER (__FUNCTION__); memset (&txa, 0x0, sizeof(txa)); sng_cc_con_status(1, sngss7_info->suInstId, sngss7_info->spInstId, sngss7_info->circuit->id, &txa, CHARGE_ACK); SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx TXA\n", sngss7_info->circuit->cic); #endif SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; }
ftdm_status_t get_facility_ie_str(ftdm_channel_t *ftdmchan, uint8_t *data, uint8_t data_len) { sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; if (signal_data->facility_ie_decode == SNGISDN_OPT_FALSE) { /* Max size of Facility IE is 255 */ uint8_t my_data [255]; /* Always include Facility IE identifier + len so this can be used as a sanity check by the user */ my_data[0] = SNGISDN_Q931_FACILITY_IE_ID; my_data[1] = data_len; memcpy(&my_data[2], data, data_len); sngisdn_add_raw_data((sngisdn_chan_data_t*)ftdmchan->call_data, my_data, data_len+2); ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Raw Facility IE copied available\n"); } else { /* Call libsng_isdn to process facility IE's here */ } return FTDM_SUCCESS; }
/* No one calls this function yet, but it has been implemented to complement TXA messages */ void ft_to_sngss7_itx (ftdm_channel_t * ftdmchan) { #ifndef SANGOMA_SPIROU SS7_FUNC_TRACE_ENTER (__FUNCTION__); ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "ITX message not supported!, please update your libsng_ss7\n"); #else const char* var = NULL; sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; SiCnStEvnt itx; SS7_FUNC_TRACE_ENTER (__FUNCTION__); memset (&itx, 0x0, sizeof (itx)); itx.msgNum.eh.pres = PRSNT_NODEF; itx.msgNum.msgNum.pres = PRSNT_NODEF; var = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_itx_msg_num"); if (!ftdm_strlen_zero(var)) { itx.msgNum.msgNum.val = atoi(var); } else { itx.msgNum.msgNum.val = 0x1; } itx.chargUnitNum.eh.pres = PRSNT_NODEF; itx.chargUnitNum.chargUnitNum.pres = PRSNT_NODEF; var = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_itx_charge_unit"); if (!ftdm_strlen_zero(var)) { itx.chargUnitNum.chargUnitNum.val = atoi(var); } else { itx.chargUnitNum.chargUnitNum.val = 0x1; } ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "ITX Charging Unit:%d Msg Num:%d\n", itx.chargUnitNum.chargUnitNum.val, itx.msgNum.msgNum.val); sng_cc_con_status (1, sngss7_info->suInstId, sngss7_info->spInstId, sngss7_info->circuit->id, &itx, CHARGE_UNIT); SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx ITX\n", sngss7_info->circuit->cic); #endif SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; }
ftdm_status_t get_callref(ftdm_channel_t *ftdmchan, BCCallRef* callRef) { sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data; if (signal_data->raw_trace_q931) { if (callRef->eh.pres != PRSNT_NODEF || callRef->reference.pres != PRSNT_NODEF) { /* Netborder only supports BRI, so we only care for BRI for now */ if (FTDM_SPAN_IS_BRI(ftdmchan->span) && !sngisdn_info->call_ref) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Failed to obtain call reference\n"); } return FTDM_FAIL; } if (FTDM_SPAN_IS_BRI(ftdmchan->span)) { sngisdn_info->call_ref = 0x7F & callRef->reference.val; } else { sngisdn_info->call_ref = 0x7FFF & callRef->reference.val; } ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Call reference:%04x\n", sngisdn_info->call_ref); } return FTDM_SUCCESS; }
static ftdm_status_t ftdm_gsm_state_advance(ftdm_channel_t *ftdmchan) { ftdm_log_chan(ftdmchan, STATE_ADVANCE_LOG_LEVEL , "Executing state handler for %s\n", ftdm_channel_state2str(ftdmchan->state)); ftdm_channel_complete_state(ftdmchan); switch (ftdmchan->state) { /* starting an incoming call */ case FTDM_CHANNEL_STATE_COLLECT: { } break; /* starting an outgoing call */ case FTDM_CHANNEL_STATE_DIALING: { uint32_t interval = 0; ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Starting outgoing call with interval %d\n", interval); { ftdm_gsm_span_data_t *gsm_data; gsm_data = ftdmchan->span->signal_data; gsm_data->call_id = g_outbound_call_id++; wat_con_event_t con_event; memset(&con_event, 0, sizeof(con_event)); ftdm_set_string(con_event.called_num.digits, ftdmchan->caller_data.dnis.digits); ftdm_log(FTDM_LOG_DEBUG, "Dialing number %s\n", con_event.called_num.digits); wat_con_req(ftdmchan->span->span_id, gsm_data->call_id , &con_event); SEND_STATE_SIGNAL(FTDM_SIGEVENT_DIALING); } } break; /* incoming call was offered */ case FTDM_CHANNEL_STATE_RING: /* notify the user about the new call */ ftdm_log(FTDM_LOG_INFO, "Answering Incomming Call\r\n"); SEND_STATE_SIGNAL(FTDM_SIGEVENT_START); break; /* the call is making progress */ case FTDM_CHANNEL_STATE_PROGRESS: case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: { SEND_STATE_SIGNAL(FTDM_SIGEVENT_PROGRESS_MEDIA); ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP); } break; /* the call was answered */ case FTDM_CHANNEL_STATE_UP: { if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { SEND_STATE_SIGNAL(FTDM_SIGEVENT_UP); } else { ftdm_gsm_span_data_t *gsm_data; gsm_data = ftdmchan->span->signal_data; wat_con_cfm(ftdmchan->span->span_id, gsm_data->call_id); } } break; /* just got hangup */ case FTDM_CHANNEL_STATE_HANGUP: { ftdm_gsm_span_data_t *gsm_data; gsm_data = ftdmchan->span->signal_data; wat_rel_req(ftdmchan->span->span_id, gsm_data->call_id); gsm_data->call_id = 0; SEND_STATE_SIGNAL(FTDM_SIGEVENT_STOP); } break; case FTDM_CHANNEL_STATE_TERMINATING: { SEND_STATE_SIGNAL(FTDM_SIGEVENT_STOP); } break; /* finished call for good */ case FTDM_CHANNEL_STATE_DOWN: { ftdm_channel_t *closed_chan; closed_chan = ftdmchan; ftdm_channel_close(&closed_chan); ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "State processing ended.\n"); SEND_STATE_SIGNAL(FTDM_SIGEVENT_STOP); } break; /* INDICATE_RINGING doesn't apply to MFC/R2. maybe we could generate a tone */ case FTDM_CHANNEL_STATE_RINGING: ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "RINGING indicated, ignoring it as it doesn't apply to MFC/R2\n"); SEND_STATE_SIGNAL(FTDM_SIGEVENT_RINGING); break; /* put the r2 channel back to IDLE, close ftdmchan and set it's state as DOWN */ case FTDM_CHANNEL_STATE_RESET: { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "RESET indicated, putting the R2 channel back to IDLE\n"); ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); } break; default: { ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Unhandled channel state change: %s\n", ftdm_channel_state2str(ftdmchan->state)); } break; } return FTDM_SUCCESS; }
/* Remote side transmit a SETUP */ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); int16_t suId = sngisdn_event->suId; uint32_t suInstId = sngisdn_event->suInstId; uint32_t spInstId = sngisdn_event->spInstId; int16_t dChan = sngisdn_event->dChan; uint8_t ces = sngisdn_event->ces; sngisdn_chan_data_t *sngisdn_info = sngisdn_event->sngisdn_info; ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan; sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; ConEvnt *conEvnt = &sngisdn_event->event.conEvnt; ftdm_assert(!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE), "State change flag pending\n"); ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_DEBUG, "Processing SETUP (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_DOWN: /* Proper state to receive a SETUP */ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE) || ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Received SETUP but channel is in USE, saving call for later processing\n"); /* the flag the channel as having a collision */ sngisdn_set_flag(sngisdn_info, FLAG_GLARE); /* save the SETUP for processing once the channel has gone to DOWN */ memcpy(&sngisdn_info->glare.setup, conEvnt, sizeof(*conEvnt)); sngisdn_info->glare.suId = suId; sngisdn_info->glare.suInstId = suInstId; /* Do not generate a suInstId now, we will generate when glared call gets extracted */ sngisdn_info->glare.spInstId = spInstId; sngisdn_info->glare.dChan = dChan; sngisdn_info->glare.ces = ces; break; } sngisdn_info->suInstId = get_unique_suInstId(suId); sngisdn_info->spInstId = spInstId; /* If this is a glared call that was previously saved, we moved all the info to the current call, so clear the glared saved data */ if (sngisdn_info->glare.spInstId == spInstId) { clear_call_glare_data(sngisdn_info); } ftdm_mutex_lock(g_sngisdn_data.ccs[suId].mutex); g_sngisdn_data.ccs[suId].active_suInstIds[sngisdn_info->suInstId] = sngisdn_info; ftdm_mutex_unlock(g_sngisdn_data.ccs[suId].mutex); ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND); if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP && signal_data->signalling == SNGISDN_SIGNALING_NET) { sngisdn_info->ces = ces; } /* try to open the channel */ if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Failed to open channel"); sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_REL); ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_TEMPORARY_FAILURE; ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_CANCEL); break; } #if 0 /* Export ftdmchan variables here if we need to */ ftdm_channel_add_var(ftdmchan, "isdn_specific_var", "1"); ftdm_channel_add_var(ftdmchan, "isdn_crap", "morecrap"); ftdm_channel_add_var(ftdmchan, "isdn_stuff", "s"); ftdm_channel_add_var(ftdmchan, "isdn_d", "asdsadasdasdsad"); #endif /* Fill in call information */ cpy_calling_num_from_stack(&ftdmchan->caller_data, &conEvnt->cgPtyNmb); cpy_called_num_from_stack(&ftdmchan->caller_data, &conEvnt->cdPtyNmb); cpy_calling_name_from_stack(&ftdmchan->caller_data, &conEvnt->display); if (conEvnt->bearCap[0].eh.pres) { ftdmchan->caller_data.bearer_layer1 = sngisdn_get_infoTranCap_from_stack(conEvnt->bearCap[0].usrInfoLyr1Prot.val); ftdmchan->caller_data.bearer_capability = sngisdn_get_infoTranCap_from_stack(conEvnt->bearCap[0].infoTranCap.val); } if (signal_data->switchtype == SNGISDN_SWITCH_NI2) { if (conEvnt->shift11.eh.pres && conEvnt->ni2OctStr.eh.pres) { if (conEvnt->ni2OctStr.str.len == 4 && conEvnt->ni2OctStr.str.val[0] == 0x37) { snprintf(ftdmchan->caller_data.aniII, 5, "%.2d", conEvnt->ni2OctStr.str.val[3]); } } if (signal_data->facility == SNGISDN_OPT_TRUE && conEvnt->facilityStr.eh.pres) { /* Verify whether the Caller Name will come in a subsequent FACILITY message */ uint16_t ret_val; char retrieved_str[255]; ret_val = sng_isdn_retrieve_facility_caller_name(conEvnt->facilityStr.facilityStr.val, conEvnt->facilityStr.facilityStr.len, retrieved_str); /* return values for "sng_isdn_retrieve_facility_information_following": If there will be no information following, or fails to decode IE, returns -1 If there will be no information following, but current FACILITY IE contains a caller name, returns 0 If there will be information following, returns 1 */ if (ret_val == 1) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Expecting Caller name in FACILITY\n"); ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_GET_CALLERID); /* Launch timer in case we never get a FACILITY msg */ if (signal_data->facility_timeout) { ftdm_sched_timer(signal_data->sched, "facility_timeout", signal_data->facility_timeout, sngisdn_facility_timeout, (void*) sngisdn_info, &sngisdn_info->timers[SNGISDN_TIMER_FACILITY]); } break; } else if (ret_val == 0) { strcpy(ftdmchan->caller_data.cid_name, retrieved_str); } } } if (signal_data->overlap_dial == SNGISDN_OPT_TRUE && !conEvnt->sndCmplt.eh.pres) { ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_COLLECT); } else { ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); } break; case FTDM_CHANNEL_STATE_TERMINATING: ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Processing SETUP in TERMINATING state, saving SETUP info for later processing\n"); ftdm_assert(!sngisdn_test_flag(sngisdn_info, FLAG_GLARE), "Trying to save GLARE info, but we already had a glare\n"); sngisdn_set_flag(sngisdn_info, FLAG_GLARE); /* save the SETUP for processing once the channel has gone to DOWN */ memcpy(&sngisdn_info->glare.setup, conEvnt, sizeof(*conEvnt)); sngisdn_info->glare.suId = suId; sngisdn_info->glare.suInstId = suInstId; /* Do not generate a suInstId now, we will generate when glared call gets extracted */ sngisdn_info->glare.spInstId = spInstId; sngisdn_info->glare.dChan = dChan; sngisdn_info->glare.ces = ces; break; case FTDM_CHANNEL_STATE_DIALING: /* glare */ if (signal_data->signalling == SNGISDN_SIGNALING_NET) { /* Save inbound call info so we can send a RELEASE when this channel goes to a different state */ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Processing SETUP in DIALING state, rejecting inbound call\n"); sngisdn_set_flag(sngisdn_info, FLAG_DELAYED_REL); sngisdn_info->glare.suId = suId; sngisdn_info->glare.suInstId = get_unique_suInstId(suId); sngisdn_info->glare.spInstId = spInstId; sngisdn_info->glare.dChan = dChan; sngisdn_info->glare.ces = ces; ftdmchan->caller_data.hangup_cause = 0x2C; /* Channel requested not available */ ftdm_sched_timer(signal_data->sched, "delayed_release", 1, sngisdn_delayed_release, (void*) sngisdn_info, NULL); } else { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Processing SETUP in DIALING state, saving SETUP info for later processing\n"); /* the flag the channel as having a collision */ ftdm_assert(!sngisdn_test_flag(sngisdn_info, FLAG_GLARE), "Trying to save GLARE info, but we already had a glare"); sngisdn_set_flag(sngisdn_info, FLAG_GLARE); /* save the SETUP for processing once the channel has gone to DOWN */ memcpy(&sngisdn_info->glare.setup, conEvnt, sizeof(*conEvnt)); sngisdn_info->glare.suId = suId; sngisdn_info->glare.suInstId = suInstId; /* Do not generate a suInstId now, we will generate when glared call gets extracted */ sngisdn_info->glare.spInstId = spInstId; sngisdn_info->glare.dChan = dChan; sngisdn_info->glare.ces = ces; ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); } break; default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Processing SETUP in an invalid state (%s)\n", ftdm_channel_state2str(ftdmchan->state)); break; } ISDN_FUNC_TRACE_EXIT(__FUNCTION__); return; }
void sngisdn_process_rel_ind (sngisdn_event_data_t *sngisdn_event) { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); int16_t suId = sngisdn_event->suId; uint32_t suInstId = sngisdn_event->suInstId; uint32_t spInstId = sngisdn_event->spInstId; sngisdn_chan_data_t *sngisdn_info = sngisdn_event->sngisdn_info; ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan; RelEvnt *relEvnt = &sngisdn_event->event.relEvnt; ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Processing RELEASE/RELEASE COMPLETE (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); ftdm_assert(!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE), "State change flag pending\n"); if ((suInstId && (sngisdn_info->glare.suInstId == suInstId)) || (spInstId && (sngisdn_info->glare.spInstId == spInstId))) { /* This hangup is for a glared saved call */ ftdm_clear_flag(sngisdn_info, FLAG_DELAYED_REL); clear_call_glare_data(sngisdn_info); ISDN_FUNC_TRACE_EXIT(__FUNCTION__); return; } /* check whether the ftdm channel is in a state to accept a call */ switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_HANGUP_COMPLETE: /* go to DOWN */ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); break; case FTDM_CHANNEL_STATE_DOWN: /* do nothing, just drop the message */ break; case FTDM_CHANNEL_STATE_DIALING: /* Remote side rejected our SETUP message on outbound call */ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SIG_UP)) { sng_isdn_set_avail_rate(ftdmchan->span, SNGISDN_AVAIL_DOWN); } /* fall-through */ case FTDM_CHANNEL_STATE_PROGRESS: case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: case FTDM_CHANNEL_STATE_UP: case FTDM_CHANNEL_STATE_RING: /* If we previously had a glare on this channel, this RELEASE could be for the previous call. Confirm whether call_data has not changed while we were waiting for ftdmchan->mutex by comparing suInstId's */ if (((sngisdn_chan_data_t*)ftdmchan->call_data)->suInstId == suInstId || ((sngisdn_chan_data_t*)ftdmchan->call_data)->spInstId == spInstId) { if (relEvnt->causeDgn[0].eh.pres && relEvnt->causeDgn[0].causeVal.pres) { ftdmchan->caller_data.hangup_cause = relEvnt->causeDgn[0].causeVal.val; ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "cause:%d\n", ftdmchan->caller_data.hangup_cause); } else { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "RELEASE COMPLETE did not have a cause code\n"); ftdmchan->caller_data.hangup_cause = 0; } sngisdn_set_flag(sngisdn_info, FLAG_REMOTE_ABORT); ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); } else { ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "RELEASE was for previous call (suInstId:%u spInstId:%u)\n", suInstId, spInstId); } break; case FTDM_CHANNEL_STATE_COLLECT: case FTDM_CHANNEL_STATE_GET_CALLERID: ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_CANCEL); break; case FTDM_CHANNEL_STATE_TERMINATING: if (sngisdn_test_flag(sngisdn_info, FLAG_GLARE) && sngisdn_info->glare.suInstId != suInstId) { /* This release if for the outbound call that we already started clearing */ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Received RELEASE for local glared call\n"); sngisdn_set_flag(sngisdn_info, FLAG_REMOTE_ABORT); } else { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Received release before we could clear local call\n"); /* FS core took too long to respond to the SIG STOP event */ sngisdn_set_flag(sngisdn_info, FLAG_REMOTE_ABORT); /* set abort flag so that we do not transmit another release complete on this channel once FS core is done */ } break; default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Received RELEASE in an invalid state (%s)\n", ftdm_channel_state2str(ftdmchan->state)); break; } ISDN_FUNC_TRACE_EXIT(__FUNCTION__); return; }
/** * \brief Executes an FreeTDM command on a Wanpipe channel * \param ftdmchan Channel to execute command on * \param command FreeTDM command to execute * \param obj Object (unused) * \return Success or failure */ static FIO_COMMAND_FUNCTION(wanpipe_command) { wanpipe_tdm_api_t tdm_api; int err = 0; memset(&tdm_api, 0, sizeof(tdm_api)); switch(command) { case FTDM_COMMAND_OFFHOOK: { err=sangoma_tdm_txsig_offhook(ftdmchan->sockfd,&tdm_api); if (err) { snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "OFFHOOK Failed"); return FTDM_FAIL; } ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK); } break; case FTDM_COMMAND_ONHOOK: { err=sangoma_tdm_txsig_onhook(ftdmchan->sockfd,&tdm_api); if (err) { snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ONHOOK Failed"); return FTDM_FAIL; } ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK); } break; case FTDM_COMMAND_GENERATE_RING_ON: { err=sangoma_tdm_txsig_start(ftdmchan->sockfd,&tdm_api); if (err) { snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Ring Failed"); return FTDM_FAIL; } ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_RINGING); ftdm_set_pflag_locked(ftdmchan, WP_RINGING); ftdmchan->ring_time = ftdm_current_time_in_ms() + wp_globals.ring_on_ms; } break; case FTDM_COMMAND_GENERATE_RING_OFF: { err=sangoma_tdm_txsig_offhook(ftdmchan->sockfd,&tdm_api); if (err) { snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Ring-off Failed"); return FTDM_FAIL; } ftdm_clear_pflag_locked(ftdmchan, WP_RINGING); ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_RINGING); } break; case FTDM_COMMAND_GET_INTERVAL: { err=sangoma_tdm_get_usr_period(ftdmchan->sockfd, &tdm_api); if (err > 0 ) { FTDM_COMMAND_OBJ_INT = err; err=0; } } break; case FTDM_COMMAND_ENABLE_ECHOCANCEL: { err=sangoma_tdm_enable_hwec(ftdmchan->sockfd, &tdm_api); if (err) { snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "HWEC Enable Failed"); return FTDM_FAIL; } } break; case FTDM_COMMAND_DISABLE_ECHOCANCEL: { err=sangoma_tdm_disable_hwec(ftdmchan->sockfd, &tdm_api); if (err) { snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "HWEC Disable Failed"); return FTDM_FAIL; } } break; case FTDM_COMMAND_ENABLE_DTMF_DETECT: { #ifdef WP_API_FEATURE_DTMF_EVENTS err = sangoma_tdm_enable_dtmf_events(ftdmchan->sockfd, &tdm_api); if (err) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Enabling of Sangoma HW DTMF failed\n"); snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "HW DTMF Enable Failed"); return FTDM_FAIL; } ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Enabled DTMF events\n"); #else return FTDM_NOTIMPL; #endif } break; case FTDM_COMMAND_DISABLE_DTMF_DETECT: { #ifdef WP_API_FEATURE_DTMF_EVENTS err = sangoma_tdm_disable_dtmf_events(ftdmchan->sockfd, &tdm_api); if (err) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Disabling of Sangoma HW DTMF failed\n"); snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "HW DTMF Disable Failed"); return FTDM_FAIL; } ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Disabled DTMF events\n"); #else return FTDM_NOTIMPL; #endif } break; case FTDM_COMMAND_ENABLE_LOOP: { #ifdef WP_API_FEATURE_LOOP err=sangoma_tdm_enable_loop(ftdmchan->sockfd, &tdm_api); if (err) { snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Loop Enable Failed"); return FTDM_FAIL; } #endif } break; case FTDM_COMMAND_DISABLE_LOOP: { #ifdef WP_API_FEATURE_LOOP err=sangoma_tdm_disable_loop(ftdmchan->sockfd, &tdm_api); if (err) { snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Loop Disable Failed"); return FTDM_FAIL; } #endif } break; case FTDM_COMMAND_SET_INTERVAL: { err=sangoma_tdm_set_usr_period(ftdmchan->sockfd, &tdm_api, FTDM_COMMAND_OBJ_INT); ftdmchan->packet_len = ftdmchan->native_interval * (ftdmchan->effective_codec == FTDM_CODEC_SLIN ? 16 : 8); } break; case FTDM_COMMAND_SET_CAS_BITS: { #ifdef LIBSANGOMA_VERSION err = sangoma_tdm_write_rbs(ftdmchan->sockfd,&tdm_api, ftdmchan->physical_chan_id, wanpipe_swap_bits(FTDM_COMMAND_OBJ_INT)); #else err = sangoma_tdm_write_rbs(ftdmchan->sockfd, &tdm_api, wanpipe_swap_bits(FTDM_COMMAND_OBJ_INT)); #endif } break; case FTDM_COMMAND_GET_CAS_BITS: { #ifdef LIBSANGOMA_VERSION unsigned char rbsbits; err = sangoma_tdm_read_rbs(ftdmchan->sockfd, &tdm_api, ftdmchan->physical_chan_id, &rbsbits); if (!err) { FTDM_COMMAND_OBJ_INT = wanpipe_swap_bits(rbsbits); } #else // does sangoma_tdm_read_rbs is available here? FTDM_COMMAND_OBJ_INT = ftdmchan->rx_cas_bits; #endif } break; case FTDM_COMMAND_SET_LINK_STATUS: { ftdm_channel_hw_link_status_t status = FTDM_COMMAND_OBJ_INT; char sangoma_status = status == FTDM_HW_LINK_CONNECTED ? FE_CONNECTED : FE_DISCONNECTED; err = sangoma_tdm_set_fe_status(ftdmchan->sockfd, &tdm_api, sangoma_status); } break; case FTDM_COMMAND_GET_LINK_STATUS: { unsigned char sangoma_status = 0; err = sangoma_tdm_get_fe_status(ftdmchan->sockfd, &tdm_api, &sangoma_status); if (!err) { FTDM_COMMAND_OBJ_INT = sangoma_status == FE_CONNECTED ? FTDM_HW_LINK_CONNECTED : FTDM_HW_LINK_DISCONNECTED; } } break; default: break; }; if (err) { snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno)); return FTDM_FAIL; } return FTDM_SUCCESS; }
void sngisdn_process_sta_cfm (sngisdn_event_data_t *sngisdn_event) { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); int16_t suId = sngisdn_event->suId; uint32_t suInstId = sngisdn_event->suInstId; uint32_t spInstId = sngisdn_event->spInstId; sngisdn_chan_data_t *sngisdn_info = sngisdn_event->sngisdn_info; ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan; StaEvnt *staEvnt = &sngisdn_event->event.staEvnt; uint8_t call_state = 0; if (staEvnt->callSte.eh.pres && staEvnt->callSte.callGlblSte.pres) { call_state = staEvnt->callSte.callGlblSte.val; } ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Processing STATUS CONFIRM (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); ftdm_assert(!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE), "State change flag pending\n"); if (staEvnt->causeDgn[0].eh.pres && staEvnt->causeDgn[0].causeVal.pres) { if (staEvnt->callSte.eh.pres && staEvnt->callSte.callGlblSte.pres) { call_state = staEvnt->callSte.callGlblSte.val; } else { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Received STATUS without call state\n"); ISDN_FUNC_TRACE_EXIT(__FUNCTION__); return; } switch (staEvnt->causeDgn[0].causeVal.val) { case FTDM_CAUSE_RESPONSE_TO_STATUS_ENQUIRY: ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Status Check OK:%d", call_state); ISDN_FUNC_TRACE_EXIT(__FUNCTION__); return; case FTDM_CAUSE_WRONG_CALL_STATE: ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Message incompatible with call state (call_state:%d channel-state:%s cause:%d) (suId:%u suInstId:%u spInstId:%u)\n", call_state, ftdm_channel_state2str(ftdmchan->state), staEvnt->causeDgn[0].causeVal.val, suId, suInstId, spInstId); break; case FTDM_CAUSE_RECOVERY_ON_TIMER_EXPIRE: ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Recovery on timer expire (call_state:%d channel-state:%s cause:%d) (suId:%u suInstId:%u spInstId:%u)\n", call_state, ftdm_channel_state2str(ftdmchan->state), staEvnt->causeDgn[0].causeVal.val, suId, suInstId, spInstId); break; default: ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "STATUS CONFIRM (call_state:%d channel-state:%s cause:%d) (suId:%u suInstId:%u spInstId:%u)\n", call_state, ftdm_channel_state2str(ftdmchan->state), staEvnt->causeDgn[0].causeVal.val, suId, suInstId, spInstId); break; } /* Section 4.3.30 from INT Interface - Service Definition */ ftdmchan->caller_data.hangup_cause = staEvnt->causeDgn[0].causeVal.val; switch(call_state) { /* Sere ITU-T Q931 for definition of call states */ case 0: /* Remote switch thinks there are no calls on this channel */ switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_COLLECT: case FTDM_CHANNEL_STATE_DIALING: case FTDM_CHANNEL_STATE_UP: sngisdn_set_flag(sngisdn_info, FLAG_REMOTE_ABORT); ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); break; case FTDM_CHANNEL_STATE_TERMINATING: /* We are in the process of clearing local states, just make sure we will not send any messages to remote switch */ sngisdn_set_flag(sngisdn_info, FLAG_REMOTE_ABORT); break; case FTDM_CHANNEL_STATE_HANGUP: /* This cannot happen, state_advance always sets ftdmchan to STATE_HANGUP_COMPLETE when in STATE_HANGUP and we called check_for_state_change earlier so something is very wrong here!!! */ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "How can we we in FTDM_CHANNEL_STATE_HANGUP after checking for state change?\n"); ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); break; case FTDM_CHANNEL_STATE_HANGUP_COMPLETE: /* We were waiting for remote switch to send RELEASE COMPLETE but this will not happen, so just clear local state */ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); break; case FTDM_CHANNEL_STATE_DOWN: /* If our local state is down as well, then there is nothing to do */ break; default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state)); break; } break; case 1: switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_UP: /* Remote side is still waiting for our CONNECT message */ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { ftdm_sched_timer(((sngisdn_span_data_t*)ftdmchan->span->signal_data)->sched, "delayed_connect", 1, sngisdn_delayed_connect, (void*) sngisdn_info, NULL); break; } /* Fall-through */ default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state)); break; } break; case 2: /* overlap sending/receiving */ switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_COLLECT: /* T302 Timeout reached */ /* Send the call to user, and see if they accept it */ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "T302 Timer expired, proceeding with call\n"); ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); break; case FTDM_CHANNEL_STATE_PROGRESS: case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Remote switch expecting OVERLAP receive, but we are already PROCEEDING\n"); sngisdn_snd_disconnect(ftdmchan); break; case FTDM_CHANNEL_STATE_DOWN: case FTDM_CHANNEL_STATE_HANGUP_COMPLETE: /* We hung up locally, but remote switch doesn't know send disconnect again*/ sngisdn_snd_disconnect(ftdmchan); break; default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state)); break; } break; case 3: switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_PROGRESS: /* T310 timer has expired */ ftdmchan->caller_data.hangup_cause = staEvnt->causeDgn[0].causeVal.val; ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "T310 Timer expired, hanging up call\n"); sngisdn_set_flag(sngisdn_info, FLAG_SEND_DISC); ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); break; case FTDM_CHANNEL_STATE_UP: /* Remote side is still waiting for our CONNECT message */ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { ftdm_sched_timer(((sngisdn_span_data_t*)ftdmchan->span->signal_data)->sched, "delayed_connect", 1, sngisdn_delayed_connect, (void*) sngisdn_info, NULL); break; } /* Fall-through */ default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state)); break; } break; case 8: /* Remote switch is in "Connect Request state" */ switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_UP: /* This is ok. We sent a Connect, and we are waiting for a connect ack */ /* Do nothing */ break; case FTDM_CHANNEL_STATE_HANGUP_COMPLETE: /* We hung up locally, but remote switch doesn't know send disconnect again*/ sngisdn_snd_disconnect(ftdmchan); break; default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state)); break; } break; case 9: /* Remote switch is in "Incoming call proceeding" state */ switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_PROGRESS: case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: case FTDM_CHANNEL_STATE_GET_CALLERID: /* Do nothing */ break; case FTDM_CHANNEL_STATE_UP: /* Remote switch missed our CONNECT message, re-send */ ftdm_sched_timer(((sngisdn_span_data_t*)ftdmchan->span->signal_data)->sched, "delayed_connect", 1, sngisdn_delayed_connect, (void*) sngisdn_info, NULL); break; default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state)); break; } break; case 10: /* Remote switch is in active state */ switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_UP: /* This is ok, they are in active state and we are in active state */ /* Do nothing */ break; case FTDM_CHANNEL_STATE_HANGUP_COMPLETE: /* We sent a disconnect message, but remote side missed it ? */ ftdm_sched_timer(((sngisdn_span_data_t*)ftdmchan->span->signal_data)->sched, "delayed_disconnect", 1, sngisdn_delayed_disconnect, (void*) sngisdn_info, NULL); break; default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state)); break; } break; case 22: switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_UP: /* Stack is in the process of clearing the call*/ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); break; case FTDM_CHANNEL_STATE_HANGUP_COMPLETE: /* Do nothing as we will get a RELEASE COMPLETE */ break; default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state)); //ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); break; } default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state)); //ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); break; } } ISDN_FUNC_TRACE_EXIT(__FUNCTION__); return; }