void sngisdn_set_span_sig_status(ftdm_span_t *span, ftdm_signaling_status_t status)
{
	ftdm_iterator_t *chaniter = NULL;
	ftdm_iterator_t *curr = NULL;


	chaniter = ftdm_span_get_chan_iterator(span, NULL);
	for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
		sngisdn_set_chan_sig_status(((ftdm_channel_t*)ftdm_iterator_current(curr)), status);
	}
	ftdm_iterator_free(chaniter);
	return;
}
ftdm_status_t sngisdn_set_span_avail_rate(ftdm_span_t *span, sngisdn_avail_t avail)
{
	if (FTDM_SPAN_IS_BRI(span)) {
		ftdm_iterator_t *chaniter = NULL;
		ftdm_iterator_t *curr = NULL;

		chaniter = ftdm_span_get_chan_iterator(span, NULL);
		for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
			ftdm_log_chan(((ftdm_channel_t*)ftdm_iterator_current(curr)), FTDM_LOG_DEBUG, "Setting availability rate to:%d\n", avail);
			sngisdn_set_chan_avail_rate(((ftdm_channel_t*)ftdm_iterator_current(curr)), avail);
		}
		ftdm_iterator_free(chaniter);
	}
	return FTDM_SUCCESS;
}
static ftdm_status_t sngisdn_map_call(sngisdn_span_data_t *signal_data, sngisdn_frame_info_t frame_info, ftdm_channel_t **found)
{
    sngisdn_chan_data_t *sngisdn_info;
    ftdm_channel_t *ftdmchan = NULL;
    ftdm_iterator_t *chaniter = NULL;
    ftdm_iterator_t *curr = NULL;
    ftdm_status_t status = FTDM_FAIL;
    uint8_t outbound_call = 0;

    if ((!frame_info.call_ref_flag && frame_info.dir == FTDM_TRACE_DIR_OUTGOING) ||
            (frame_info.call_ref_flag && frame_info.dir == FTDM_TRACE_DIR_INCOMING)) {

        /* If this is an outgoing frame and this frame was sent by the originating side
        	of the call (frame_info.call_ref_flag == 0), then this is an outbound call */
        outbound_call = 1;
    } else {
        outbound_call = 0;
    }

    switch (frame_info.msgtype) {
    case PROT_Q931_MSGTYPE_SETUP:
        /* We initiated this outgoing call try to match the call reference with our internal call-id*/
        if (!frame_info.bchan_no) {
            /* We were not able to determine the bchannel on this call, so we will not be able to match it anyway */
            status = FTDM_FAIL;
        }

        chaniter = ftdm_span_get_chan_iterator(signal_data->ftdm_span, NULL);
        for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
            ftdmchan = (ftdm_channel_t*)(ftdm_iterator_current(curr));
            ftdm_channel_lock(ftdmchan);

            if (outbound_call) {
                sngisdn_info = (sngisdn_chan_data_t*)ftdmchan->call_data;
                if (sngisdn_info && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
                    if (ftdmchan->caller_data.call_id && ftdmchan->physical_chan_id == frame_info.bchan_no) {

                        sngisdn_info->call_ref = frame_info.call_ref;
                        *found = ftdmchan;
                        status = FTDM_SUCCESS;
                    }
                }
            } else {
                if (ftdmchan->physical_chan_id == frame_info.bchan_no) {
                    *found = ftdmchan;
                    status = FTDM_SUCCESS;
                }
            }
            ftdm_channel_unlock(ftdmchan);
        }
        ftdm_iterator_free(chaniter);
        break;
    case PROT_Q931_MSGTYPE_ALERTING:
    case PROT_Q931_MSGTYPE_PROCEEDING:
    case PROT_Q931_MSGTYPE_PROGRESS:
    case PROT_Q931_MSGTYPE_CONNECT:
    case PROT_Q931_MSGTYPE_SETUP_ACK:
    case PROT_Q931_MSGTYPE_CONNECT_ACK:
    case PROT_Q931_MSGTYPE_USER_INFO:
    case PROT_Q931_MSGTYPE_DISCONNECT:
    case PROT_Q931_MSGTYPE_RELEASE:
    case PROT_Q931_MSGTYPE_RELEASE_ACK:
    case PROT_Q931_MSGTYPE_RELEASE_COMPLETE:
    case PROT_Q931_MSGTYPE_FACILITY:
    case PROT_Q931_MSGTYPE_NOTIFY:
    case PROT_Q931_MSGTYPE_STATUS_ENQUIRY:
    case PROT_Q931_MSGTYPE_INFORMATION:
    case PROT_Q931_MSGTYPE_STATUS:
        /* Look for an outbound call on that span and and try to match the call-id */
        chaniter = ftdm_span_get_chan_iterator(signal_data->ftdm_span, NULL);
        for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
            ftdmchan = (ftdm_channel_t*)(ftdm_iterator_current(curr));
            ftdm_channel_lock(ftdmchan);
            sngisdn_info = (sngisdn_chan_data_t*)ftdmchan->call_data;
            if (outbound_call) {
                if (sngisdn_info && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
                    if (sngisdn_info->call_ref == frame_info.call_ref) {

                        *found = ftdmchan;
                        status = FTDM_SUCCESS;
                    }
                }
            } else {
                if (sngisdn_info && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
                    if (sngisdn_info->call_ref && sngisdn_info->call_ref == frame_info.call_ref) {

                        *found = ftdmchan;
                        status = FTDM_SUCCESS;
                    }
                }
            }
            ftdm_channel_unlock(ftdmchan);
        }
        ftdm_iterator_free(chaniter);
        break;
    default:
        /* This frame is not call specific, ignore */
        break;
    }
    if (status == FTDM_SUCCESS) {
        ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Mapped %s with Call Ref:%04x to call-id:%d\n", get_code_2_str(frame_info.msgtype, dcodQ931MsgTypeTable), frame_info.call_ref, (*found)->caller_data.call_id);
    } else {
        /* We could not map this frame to a call-id */
        ftdm_log(FTDM_LOG_DEBUG, "Failed to map %s with Call Ref:%04x to local call\n",
                 get_code_2_str(frame_info.msgtype, dcodQ931MsgTypeTable), frame_info.call_ref);
    }

    return status;
}
Example #4
0
static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_gsm_configure_span_signaling)
{
	wat_span_config_t span_config;
	ftdm_gsm_span_data_t *gsm_data = NULL;
	ftdm_iterator_t *chaniter = NULL;
	ftdm_iterator_t *citer = NULL;
	ftdm_channel_t *ftdmchan = NULL;
	ftdm_channel_t *dchan = NULL;
	ftdm_channel_t *bchan = NULL;

	unsigned paramindex = 0;
	const char *var = NULL;
	const char *val = NULL;
	
	/* libwat is smart enough to set good default values for the timers if they are set to 0 */
	memset(&span_config, 0, sizeof(span_config));
	
	/* set some span defaults */
	span_config.moduletype = WAT_MODULE_TELIT;

	if (FTDM_SUCCESS != init_wat_lib()) {
		return FTDM_FAIL;
	}

	if (!sig_cb) {
		ftdm_log(FTDM_LOG_ERROR, "No signaling callback provided\n");
		return FTDM_FAIL;
	}

	if (span->signal_type) {
		ftdm_log(FTDM_LOG_ERROR, "Span %s is already configured for another signaling\n", span->name);
		return FTDM_FAIL;
	}

	/* verify the span has one d-channel */
	chaniter = ftdm_span_get_chan_iterator(span, NULL);
	
	if (!chaniter) {
		ftdm_log(FTDM_LOG_CRIT, "Failed to allocate channel iterator for span %s!\n", span->name);
		return FTDM_FAIL;
	}

	citer = ftdm_span_get_chan_iterator(span, chaniter);
	for ( ; citer; citer = ftdm_iterator_next(citer)) {
		ftdmchan = ftdm_iterator_current(citer);
		
		if ((NULL == dchan) && FTDM_IS_DCHAN(ftdmchan)) {
			dchan = ftdmchan;
		}
		if ((NULL == bchan) && FTDM_IS_VOICE_CHANNEL(ftdmchan)) {
			bchan = ftdmchan;
		}

	}
	ftdm_iterator_free(chaniter);

	if (!dchan) {
		ftdm_log(FTDM_LOG_CRIT, "Could not find a d-channel for GSM span %s!\n", span->name);
		return FTDM_FAIL;
	}
	if (!bchan) {
		ftdm_log(FTDM_LOG_CRIT, "Could not find a b-channel for GSM span %s!\n", span->name);
		return FTDM_FAIL;
	}





	gsm_data = ftdm_calloc(1, sizeof(*gsm_data));
	if (!gsm_data) {
		return FTDM_FAIL;
	}
	gsm_data->dchan = dchan;
	gsm_data->bchan = bchan;

	//sprintf(gsm_data->dchan->chan_name, "%s\t\n", "GSM dchan");
	//sprintf(gsm_data->bchan->chan_name, "%s\r\n", "GSM bchan");

	for (paramindex = 0; ftdm_parameters[paramindex].var; paramindex++) {
		var = ftdm_parameters[paramindex].var;
		val = ftdm_parameters[paramindex].val;
		if (!ftdm_strlen_zero_buf(val)) {
			ftdm_log(FTDM_LOG_WARNING, "Ignoring empty GSM parameter %s for span %s\n", var, span->name);
			continue;
		}
		ftdm_log(FTDM_LOG_DEBUG, "Reading GSM parameter %s=%s for span %s\n", var, val, span->name);
		if (!strcasecmp(var, "moduletype")) {
			span_config.moduletype = wat_str2wat_moduletype(val);
			if (span_config.moduletype == WAT_MODULE_INVALID) {
				ftdm_log(FTDM_LOG_DEBUG, "Unknown GSM module type %s for span %s\n", val, span->name);
				continue;
			}
			ftdm_log(FTDM_LOG_DEBUG, "Configuring GSM span %s with moduletype %s\n", span->name, val);
		} else {
			ftdm_log(FTDM_LOG_ERROR, "Ignoring unknown GSM parameter '%s'", var);
		}
	}

	/* Bind function pointers for control operations */
	span->start = ftdm_gsm_start;
	span->stop = ftdm_gsm_stop;
	span->sig_read = NULL;
	span->sig_write = NULL;

	span->signal_cb = sig_cb;
	span->signal_type = FTDM_SIGTYPE_GSM;
	span->signal_data = gsm_data; /* Gideon, plz fill me with gsm span specific data (you allocate and free) */
	span->outgoing_call = gsm_outgoing_call;
	span->get_span_sig_status = ftdm_gsm_get_span_sig_status;
	span->set_span_sig_status = ftdm_gsm_set_span_sig_status;
	span->get_channel_sig_status = ftdm_gsm_get_channel_sig_status;
	span->set_channel_sig_status = ftdm_gsm_set_channel_sig_status;

	//printf("\r\nspan->state_map = &gsm_state_map;\r\n");
	span->state_map = &gsm_state_map;
	span->state_processor = ftdm_gsm_state_advance;

	/* use signals queue */
	ftdm_set_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE);
	ftdm_set_flag(span, FTDM_SPAN_USE_CHAN_QUEUE);

	/* we can skip states (going straight from RING to UP) */
	ftdm_set_flag(span, FTDM_SPAN_USE_SKIP_STATES);

	gsm_data->span = span;

#if 0
	/* setup the scheduler (create if needed) */
	snprintf(schedname, sizeof(schedname), "ftmod_r2_%s", span->name);
	ftdm_assert(ftdm_sched_create(&r2data->sched, schedname) == FTDM_SUCCESS, "Failed to create schedule!\n");
	spanpvt->sched = r2data->sched;
#endif

	
fprintf(stdout, "Configuring wat span %d %s \r\n", span->span_id, span->name);
	if (wat_span_config(span->span_id, &span_config)) {
		ftdm_log(FTDM_LOG_ERROR, "Failed to configure span %s for GSM signaling!!\n", span->name);
		return FTDM_FAIL;
	}

	{
		int codec		= FTDM_CODEC_SLIN;
		int interval	= 20;
		
		ftdm_channel_command(gsm_data->bchan, FTDM_COMMAND_SET_NATIVE_CODEC,  &codec);
		ftdm_channel_command(gsm_data->bchan, FTDM_COMMAND_SET_CODEC,  &codec);
		ftdm_channel_command(gsm_data->bchan, FTDM_COMMAND_SET_INTERVAL,  &interval);
	}

	return FTDM_SUCCESS;

}
static ftdm_status_t parse_switchtype(const char* switch_name, ftdm_span_t *span)
{
	unsigned i;
	ftdm_iterator_t *chaniter = NULL;
	ftdm_iterator_t *curr = NULL;	
	//sngisdn_dchan_data_t *dchan_data;
	sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data;
	
	switch(span->trunk_type) {
		case FTDM_TRUNK_T1:
			if (!strcasecmp(switch_name, "ni2") ||
				!strcasecmp(switch_name, "national")) {
				signal_data->switchtype = SNGISDN_SWITCH_NI2;
			} else if (!strcasecmp(switch_name, "5ess")) {
				signal_data->switchtype = SNGISDN_SWITCH_5ESS;
			} else if (!strcasecmp(switch_name, "4ess")) {
				signal_data->switchtype = SNGISDN_SWITCH_4ESS;
			} else if (!strcasecmp(switch_name, "dms100")) {
				signal_data->switchtype = SNGISDN_SWITCH_DMS100;
			} else if (!strcasecmp(switch_name, "qsig")) {
				signal_data->switchtype = SNGISDN_SWITCH_QSIG;
			} else {
				ftdm_log(FTDM_LOG_ERROR, "%s:Unsupported switchtype %s for trunktype:%s\n", span->name, switch_name, ftdm_trunk_type2str(span->trunk_type));
				return FTDM_FAIL;
			}
			break;
		case FTDM_TRUNK_E1:
			if (!strcasecmp(switch_name, "euroisdn") ||
				!strcasecmp(switch_name, "etsi")) {
				signal_data->switchtype = SNGISDN_SWITCH_EUROISDN;
			} else if (!strcasecmp(switch_name, "qsig")) {
				signal_data->switchtype = SNGISDN_SWITCH_QSIG;
			} else {
				ftdm_log(FTDM_LOG_ERROR, "%s:Unsupported switchtype %s for trunktype:%s\n", span->name, switch_name, ftdm_trunk_type2str(span->trunk_type));
				return FTDM_FAIL;
			}
			break;
		case FTDM_TRUNK_BRI:
		case FTDM_TRUNK_BRI_PTMP:
			if (!strcasecmp(switch_name, "euroisdn") ||
				!strcasecmp(switch_name, "etsi")) {
				signal_data->switchtype = SNGISDN_SWITCH_EUROISDN;
			} else if (!strcasecmp(switch_name, "insnet") ||
						!strcasecmp(switch_name, "ntt")) {
				signal_data->switchtype = SNGISDN_SWITCH_INSNET;
			} else {
				ftdm_log(FTDM_LOG_ERROR, "%s:Unsupported switchtype %s for trunktype:%s\n", span->name, switch_name, ftdm_trunk_type2str(span->trunk_type));
				return FTDM_FAIL;
			}
			ftdm_set_flag(span, FTDM_SPAN_USE_AV_RATE);
			ftdm_set_flag(span, FTDM_SPAN_PWR_SAVING);
			 /* can be > 1 for some BRI variants */
			break;
		default:
			ftdm_log(FTDM_LOG_ERROR, "%s:Unsupported trunktype:%s\n", span->name, ftdm_trunk_type2str(span->trunk_type));
			return FTDM_FAIL;
	}

	/* see if we have profile with this switch_type already */
	for (i = 1; i <= g_sngisdn_data.num_cc; i++) {
		if (g_sngisdn_data.ccs[i].switchtype == signal_data->switchtype &&
			g_sngisdn_data.ccs[i].trunktype == span->trunk_type) {
			break;
		}
	}

	/* need to create a new switch_type */
	if (i > g_sngisdn_data.num_cc) {
		g_sngisdn_data.num_cc++;
		g_sngisdn_data.ccs[i].switchtype = signal_data->switchtype;
		g_sngisdn_data.ccs[i].trunktype = span->trunk_type;
		ftdm_log(FTDM_LOG_DEBUG, "%s: New switchtype:%s  cc_id:%u\n", span->name, switch_name, i);
	}

	/* add this span to its ent_cc */
	signal_data->cc_id = i;

	g_sngisdn_data.spans[signal_data->link_id] = signal_data;
	
	ftdm_log(FTDM_LOG_DEBUG, "%s: cc_id:%d link_id:%d\n", span->name, signal_data->cc_id, signal_data->link_id);
	
	chaniter = ftdm_span_get_chan_iterator(span, NULL);
	for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
		int32_t chan_id;
		ftdm_channel_t *ftdmchan = (ftdm_channel_t*)ftdm_iterator_current(curr);
		if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921) {
			/* set the d-channel */
			signal_data->dchan = ftdmchan;
		} else {
			/* Add the channels to the span */
			chan_id = ftdmchan->physical_chan_id;
			signal_data->channels[chan_id] = (sngisdn_chan_data_t*)ftdmchan->call_data;
			signal_data->num_chans++;
		}
	}
	ftdm_iterator_free(chaniter);
	return FTDM_SUCCESS;
}