/*!
 * \brief Decode the PresentedNumberUnscreened argument parameters.
 *
 * \param ctrl D channel controller for any diagnostic messages.
 * \param name Field name
 * \param tag Component tag that identified this production.
 * \param pos Starting position of the ASN.1 component length.
 * \param end End of ASN.1 decoding data buffer.
 * \param party Parameter storage to fill.
 *
 * \retval Start of the next ASN.1 component on success.
 * \retval NULL on error.
 */
const unsigned char *rose_dec_PresentedNumberUnscreened(struct pri *ctrl,
	const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
	struct rosePresentedNumberUnscreened *party)
{
	int length;
	int seq_offset;
	const unsigned char *seq_end;

	if (ctrl->debug & PRI_DEBUG_APDU) {
		pri_message(ctrl, "  %s PresentedNumberUnscreened\n", name);
	}
	switch (tag) {
	case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 0:
		if (ctrl->debug & PRI_DEBUG_APDU) {
			pri_message(ctrl, "  Explicit %s\n", asn1_tag2str(tag));
		}
		ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
		ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);

		ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
		party->presentation = 0;	/* presentationAllowedNumber */
		ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "presentationAllowedNumber", tag, pos,
			seq_end, &party->number));

		ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
		break;
	case ASN1_CLASS_CONTEXT_SPECIFIC | 1:
		party->presentation = 1;	/* presentationRestricted */
		ASN1_CALL(pos, asn1_dec_null(ctrl, "presentationRestricted", tag, pos, end));
		break;
	case ASN1_CLASS_CONTEXT_SPECIFIC | 2:
		party->presentation = 2;	/* numberNotAvailableDueToInterworking */
		ASN1_CALL(pos, asn1_dec_null(ctrl, "numberNotAvailableDueToInterworking", tag,
			pos, end));
		break;
	case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 3:
		if (ctrl->debug & PRI_DEBUG_APDU) {
			pri_message(ctrl, "  Explicit %s\n", asn1_tag2str(tag));
		}
		ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
		ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);

		ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
		party->presentation = 3;	/* presentationRestrictedNumber */
		ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "presentationRestrictedNumber", tag,
			pos, seq_end, &party->number));

		ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
		break;
	default:
		ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
		return NULL;
	}

	return pos;
}
Example #2
0
void pri_dump_event(struct pri *pri, pri_event *e)
{
	if (!pri || !e)
		return;
	pri_message(pri, "Event type: %s (%d)\n", pri_event2str(e->gen.e), e->gen.e);
	switch(e->gen.e) {
	case PRI_EVENT_DCHAN_UP:
	case PRI_EVENT_DCHAN_DOWN:
		break;
	case PRI_EVENT_CONFIG_ERR:
		pri_message(pri, "Error: %s", e->err.err);
		break;
	case PRI_EVENT_RESTART:
		pri_message(pri, "Restart on channel %d\n", e->restart.channel);
	case PRI_EVENT_RING:
		pri_message(pri, "Calling number: %s (%s, %s)\n", e->ring.callingnum, pri_plan2str(e->ring.callingplan), pri_pres2str(e->ring.callingpres));
		pri_message(pri, "Called number: %s (%s)\n", e->ring.callednum, pri_plan2str(e->ring.calledplan));
		pri_message(pri, "Channel: %d (%s) Reference number: %d\n", e->ring.channel, e->ring.flexible ? "Flexible" : "Not Flexible", e->ring.cref);
		break;
	case PRI_EVENT_HANGUP:
		pri_message(pri, "Hangup, reference number: %d, reason: %s\n", e->hangup.cref, pri_cause2str(e->hangup.cause));
		break;
	default:
		pri_message(pri, "Don't know how to dump events of type %d\n", e->gen.e);
	}
}
/*!
 * \internal
 * \brief Decode the public or private network PartyNumber argument parameters.
 *
 * \param ctrl D channel controller for any diagnostic messages.
 * \param name Field name
 * \param tag Component tag that identified this production.
 * \param pos Starting position of the ASN.1 component length.
 * \param end End of ASN.1 decoding data buffer.
 * \param party_number Parameter storage to fill.
 *
 * \retval Start of the next ASN.1 component on success.
 * \retval NULL on error.
 */
static const unsigned char *rose_dec_NetworkPartyNumber(struct pri *ctrl,
	const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
	struct rosePartyNumber *party_number)
{
	int32_t value;
	int length;
	int seq_offset;
	const unsigned char *seq_end;

	if (ctrl->debug & PRI_DEBUG_APDU) {
		pri_message(ctrl, "  %s %s\n", name, asn1_tag2str(tag));
	}
	ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
	ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);

	ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
	ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
	ASN1_CALL(pos, asn1_dec_int(ctrl, "typeOfNumber", tag, pos, seq_end, &value));
	party_number->ton = value;

	ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
	ASN1_CHECK_TAG(ctrl, tag, tag & ~ASN1_PC_MASK, ASN1_TYPE_NUMERIC_STRING);
	ASN1_CALL(pos, rose_dec_NumberDigits(ctrl, "numberDigits", tag, pos, seq_end,
		party_number));

	ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);

	return pos;
}
/*!
 * \brief Decode the EctInform invoke argument parameters.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param tag Component tag that identified this structure.
 * \param pos Starting position of the ASN.1 component length.
 * \param end End of ASN.1 decoding data buffer.
 * \param args Arguments to fill in from the decoded buffer.
 *
 * \retval Start of the next ASN.1 component on success.
 * \retval NULL on error.
 */
const unsigned char *rose_dec_etsi_EctInform_ARG(struct pri *ctrl, unsigned tag,
	const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
{
	struct roseEtsiEctInform_ARG *ect_inform;
	int length;
	int seq_offset;
	const unsigned char *seq_end;
	int32_t value;

	if (ctrl->debug & PRI_DEBUG_APDU) {
		pri_message(ctrl, "  EctInform %s\n", asn1_tag2str(tag));
	}
	ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
	ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);

	ect_inform = &args->etsi.EctInform;

	ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
	ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
	ASN1_CALL(pos, asn1_dec_int(ctrl, "callStatus", tag, pos, seq_end, &value));
	ect_inform->status = value;

	if (pos < seq_end && *pos != ASN1_INDEF_TERM) {
		ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
		ASN1_CALL(pos, rose_dec_PresentedNumberUnscreened(ctrl, "redirectionNumber", tag,
			pos, seq_end, &ect_inform->redirection));
		ect_inform->redirection_present = 1;
	} else {
		ect_inform->redirection_present = 0;
	}

	ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);

	return pos;
}
/*!
 * \internal
 * \brief Decode the MessageID argument parameters.
 *
 * \param ctrl D channel controller for any diagnostic messages.
 * \param name Field name
 * \param tag Component tag that identified this production.
 * \param pos Starting position of the ASN.1 component length.
 * \param end End of ASN.1 decoding data buffer.
 * \param msg_id Parameter storage to fill.
 *
 * \retval Start of the next ASN.1 component on success.
 * \retval NULL on error.
 */
static const unsigned char *rose_dec_etsi_message_id(struct pri *ctrl, const char *name,
	unsigned tag, const unsigned char *pos, const unsigned char *end,
	struct roseEtsiMessageID *msg_id)
{
	int32_t value;
	int length;
	int seq_offset;
	const unsigned char *seq_end;

	ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
	if (ctrl->debug & PRI_DEBUG_APDU) {
		pri_message(ctrl, "  %s MessageID %s\n", name, asn1_tag2str(tag));
	}
	ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
	ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);

	ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
	ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_INTEGER);
	ASN1_CALL(pos, asn1_dec_int(ctrl, "messageRef", tag, pos, seq_end, &value));
	msg_id->reference_number = value;

	ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
	ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
	ASN1_CALL(pos, asn1_dec_int(ctrl, "status", tag, pos, seq_end, &value));
	msg_id->status = value;

	ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);

	return pos;
}
/*!
 * \brief Decode the NumberScreened argument parameters.
 *
 * \param ctrl D channel controller for any diagnostic messages.
 * \param name Field name
 * \param tag Component tag that identified this production.
 * \param pos Starting position of the ASN.1 component length.
 * \param end End of ASN.1 decoding data buffer.
 * \param screened Parameter storage to fill.
 *
 * \retval Start of the next ASN.1 component on success.
 * \retval NULL on error.
 */
const unsigned char *rose_dec_NumberScreened(struct pri *ctrl, const char *name,
	unsigned tag, const unsigned char *pos, const unsigned char *end,
	struct roseNumberScreened *screened)
{
	int32_t value;
	int length;
	int seq_offset;
	const unsigned char *seq_end;

	if (ctrl->debug & PRI_DEBUG_APDU) {
		pri_message(ctrl, "  %s NumberScreened %s\n", name, asn1_tag2str(tag));
	}
	ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
	ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);

	ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
	ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "partyNumber", tag, pos, seq_end,
		&screened->number));

	ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
	ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
	ASN1_CALL(pos, asn1_dec_int(ctrl, "screeningIndicator", tag, pos, seq_end, &value));
	screened->screening_indicator = value;

	ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);

	return pos;
}
/*!
 * \brief Decode the PresentedAddressScreened argument parameters.
 *
 * \param ctrl D channel controller for any diagnostic messages.
 * \param name Field name
 * \param tag Component tag that identified this production.
 * \param pos Starting position of the ASN.1 component length.
 * \param end End of ASN.1 decoding data buffer.
 * \param party Parameter storage to fill.
 *
 * \retval Start of the next ASN.1 component on success.
 * \retval NULL on error.
 */
const unsigned char *rose_dec_PresentedAddressScreened(struct pri *ctrl,
	const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
	struct rosePresentedAddressScreened *party)
{
	if (ctrl->debug & PRI_DEBUG_APDU) {
		pri_message(ctrl, "  %s PresentedAddressScreened\n", name);
	}
	switch (tag) {
	case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 0:
		party->presentation = 0;	/* presentationAllowedAddress */
		ASN1_CALL(pos, rose_dec_AddressScreened(ctrl, "presentationAllowedAddress", tag,
			pos, end, &party->screened));
		break;
	case ASN1_CLASS_CONTEXT_SPECIFIC | 1:
		party->presentation = 1;	/* presentationRestricted */
		ASN1_CALL(pos, asn1_dec_null(ctrl, "presentationRestricted", tag, pos, end));
		break;
	case ASN1_CLASS_CONTEXT_SPECIFIC | 2:
		party->presentation = 2;	/* numberNotAvailableDueToInterworking */
		ASN1_CALL(pos, asn1_dec_null(ctrl, "numberNotAvailableDueToInterworking", tag,
			pos, end));
		break;
	case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 3:
		party->presentation = 3;	/* presentationRestrictedAddress */
		ASN1_CALL(pos, rose_dec_AddressScreened(ctrl, "presentationRestrictedAddress",
			tag, pos, end, &party->screened));
		break;
	default:
		ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
		return NULL;
	}

	return pos;
}
/*!
 * \brief Decode the Address argument parameters.
 *
 * \param ctrl D channel controller for any diagnostic messages.
 * \param name Field name
 * \param tag Component tag that identified this production.
 * \param pos Starting position of the ASN.1 component length.
 * \param end End of ASN.1 decoding data buffer.
 * \param address Parameter storage to fill.
 *
 * \retval Start of the next ASN.1 component on success.
 * \retval NULL on error.
 */
const unsigned char *rose_dec_Address(struct pri *ctrl, const char *name, unsigned tag,
	const unsigned char *pos, const unsigned char *end, struct roseAddress *address)
{
	int length;
	int seq_offset;
	const unsigned char *seq_end;

	if (ctrl->debug & PRI_DEBUG_APDU) {
		pri_message(ctrl, "  %s Address %s\n", name, asn1_tag2str(tag));
	}
	ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
	ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);

	ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
	ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "partyNumber", tag, pos, seq_end,
		&address->number));

	if (pos < seq_end && *pos != ASN1_INDEF_TERM) {
		/* The optional subaddress must be present since there is something left. */
		ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
		ASN1_CALL(pos, rose_dec_PartySubaddress(ctrl, "partySubaddress", tag, pos,
			seq_end, &address->subaddress));
	} else {
		address->subaddress.length = 0;	/* Subaddress not present */
	}

	ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);

	return pos;
}
static int rose_number_digits_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
{
	int i = 0;
	struct rose_component *comp = NULL;
	unsigned char *vdata = data;
	int datalen = 0;
	int res = 0;

	do {
		GET_COMPONENT(comp, i, vdata, len);
		CHECK_COMPONENT(comp, ASN1_NUMERICSTRING, "Don't know what to do with PublicPartyNumber ROSE component type 0x%x\n");
		if(comp->len > 20 && comp->len != ASN1_LEN_INDEF) {
			pri_message(pri, "!! Oversized NumberDigits component (%d)\n", comp->len);
			return -1;
		}
		if (comp->len == ASN1_LEN_INDEF) {
			datalen = strlen((char *)comp->data);
			res = datalen + 2;
		} else
			res = datalen = comp->len;
			
		memcpy(value->partyaddress, comp->data, datalen);
		value->partyaddress[datalen] = '\0';

		return res + 2;
	}
	while(0);
	
	return -1;
}
int redirectingreason_from_q931(struct pri *pri, int redirectingreason)
{
	switch(pri->switchtype) {
		case PRI_SWITCH_QSIG:
			switch(redirectingreason) {
				case PRI_REDIR_UNKNOWN:
					return QSIG_DIVERT_REASON_UNKNOWN;
				case PRI_REDIR_FORWARD_ON_BUSY:
					return QSIG_DIVERT_REASON_CFB;
				case PRI_REDIR_FORWARD_ON_NO_REPLY:
					return QSIG_DIVERT_REASON_CFNR;
				case PRI_REDIR_UNCONDITIONAL:
					return QSIG_DIVERT_REASON_CFU;
				case PRI_REDIR_DEFLECTION:
				case PRI_REDIR_DTE_OUT_OF_ORDER:
				case PRI_REDIR_FORWARDED_BY_DTE:
					pri_message(pri, "!! Don't know how to convert Q.931 redirection reason %d to Q.SIG\n", redirectingreason);
					/* Fall through */
				default:
					return QSIG_DIVERT_REASON_UNKNOWN;
			}
		default:
			switch(redirectingreason) {
				case PRI_REDIR_UNKNOWN:
					return Q952_DIVERT_REASON_UNKNOWN;
				case PRI_REDIR_FORWARD_ON_BUSY:
					return Q952_DIVERT_REASON_CFB;
				case PRI_REDIR_FORWARD_ON_NO_REPLY:
					return Q952_DIVERT_REASON_CFNR;
				case PRI_REDIR_DEFLECTION:
					return Q952_DIVERT_REASON_CD;
				case PRI_REDIR_UNCONDITIONAL:
					return Q952_DIVERT_REASON_CFU;
				case PRI_REDIR_DTE_OUT_OF_ORDER:
				case PRI_REDIR_FORWARDED_BY_DTE:
					pri_message(pri, "!! Don't know how to convert Q.931 redirection reason %d to Q.952\n", redirectingreason);
					/* Fall through */
				default:
					return Q952_DIVERT_REASON_UNKNOWN;
			}
	}
}
/*!
 * \brief Decode the MWIDeactivate invoke argument parameters.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param tag Component tag that identified this structure.
 * \param pos Starting position of the ASN.1 component length.
 * \param end End of ASN.1 decoding data buffer.
 * \param args Arguments to fill in from the decoded buffer.
 *
 * \retval Start of the next ASN.1 component on success.
 * \retval NULL on error.
 */
const unsigned char *rose_dec_etsi_MWIDeactivate_ARG(struct pri *ctrl, unsigned tag,
	const unsigned char *pos, const unsigned char *end,
	union rose_msg_invoke_args *args)
{
	int32_t value;
	int length;
	int seq_offset;
	const unsigned char *seq_end;
	struct roseEtsiMWIDeactivate_ARG *mwi_deactivate;

	mwi_deactivate = &args->etsi.MWIDeactivate;

	ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
	if (ctrl->debug & PRI_DEBUG_APDU) {
		pri_message(ctrl, "  MWIDeactivate %s\n", asn1_tag2str(tag));
	}
	ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
	ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);

	ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
	ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "receivingUserNr", tag, pos, seq_end,
		&mwi_deactivate->receiving_user_number));

	ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
	ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
	ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, seq_end, &value));
	mwi_deactivate->basic_service = value;

	/*
	 * A sequence specifies an ordered list of component types.
	 * However, for simplicity we are not checking the order of
	 * the remaining optional components.
	 */
	mwi_deactivate->controlling_user_number.length = 0;
	mwi_deactivate->mode_present = 0;
	while (pos < seq_end && *pos != ASN1_INDEF_TERM) {
		ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
		switch (tag) {
		default:
			ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "controllingUserNr", tag, pos,
				seq_end, &mwi_deactivate->controlling_user_number));
			break;
		case ASN1_TYPE_ENUMERATED:
			ASN1_CALL(pos, asn1_dec_int(ctrl, "mode", tag, pos, seq_end, &value));
			mwi_deactivate->mode = value;
			mwi_deactivate->mode_present = 1;
			break;
		}
	}

	ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);

	return pos;
}
/*!
 * \brief Decode the PartyNumber argument parameters.
 *
 * \param ctrl D channel controller for any diagnostic messages.
 * \param name Field name
 * \param tag Component tag that identified this production.
 * \param pos Starting position of the ASN.1 component length.
 * \param end End of ASN.1 decoding data buffer.
 * \param party_number Parameter storage to fill.
 *
 * \retval Start of the next ASN.1 component on success.
 * \retval NULL on error.
 */
const unsigned char *rose_dec_PartyNumber(struct pri *ctrl, const char *name,
	unsigned tag, const unsigned char *pos, const unsigned char *end,
	struct rosePartyNumber *party_number)
{
	if (ctrl->debug & PRI_DEBUG_APDU) {
		pri_message(ctrl, "  %s PartyNumber\n", name);
	}
	party_number->ton = 0;	/* unknown */
	switch (tag & ~ASN1_PC_MASK) {
	case ASN1_CLASS_CONTEXT_SPECIFIC | 0:
		party_number->plan = 0;	/* Unknown PartyNumber */
		ASN1_CALL(pos, rose_dec_NumberDigits(ctrl, "unknownPartyNumber", tag, pos, end,
			party_number));
		break;
	case ASN1_CLASS_CONTEXT_SPECIFIC | 1:
		/* Must be constructed but we will not check for it for simplicity. */
		party_number->plan = 1;	/* Public PartyNumber */
		ASN1_CALL(pos, rose_dec_NetworkPartyNumber(ctrl, "publicPartyNumber", tag, pos,
			end, party_number));
		break;
	case ASN1_CLASS_CONTEXT_SPECIFIC | 2:
		party_number->plan = 2;	/* NSAP encoded PartyNumber */
		ASN1_CALL(pos, rose_dec_NSAPPartyNumber(ctrl, "nsapEncodedPartyNumber", tag, pos,
			end, party_number));
		break;
	case ASN1_CLASS_CONTEXT_SPECIFIC | 3:
		party_number->plan = 3;	/* Data PartyNumber (Not used) */
		ASN1_CALL(pos, rose_dec_NumberDigits(ctrl, "dataPartyNumber", tag, pos, end,
			party_number));
		break;
	case ASN1_CLASS_CONTEXT_SPECIFIC | 4:
		party_number->plan = 4;	/* Telex PartyNumber (Not used) */
		ASN1_CALL(pos, rose_dec_NumberDigits(ctrl, "telexPartyNumber", tag, pos, end,
			party_number));
		break;
	case ASN1_CLASS_CONTEXT_SPECIFIC | 5:
		/* Must be constructed but we will not check for it for simplicity. */
		party_number->plan = 5;	/* Private PartyNumber */
		ASN1_CALL(pos, rose_dec_NetworkPartyNumber(ctrl, "privatePartyNumber", tag, pos,
			end, party_number));
		break;
	case ASN1_CLASS_CONTEXT_SPECIFIC | 8:
		party_number->plan = 8;	/* National Standard PartyNumber (Not used) */
		ASN1_CALL(pos, rose_dec_NumberDigits(ctrl, "nationalStandardPartyNumber", tag,
			pos, end, party_number));
		break;
	default:
		ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
		return NULL;
	}

	return pos;
}
static int redirectingreason_for_q931(struct pri *pri, int redirectingreason)
{
	switch(pri->switchtype) {
		case PRI_SWITCH_QSIG:
			switch(redirectingreason) {
				case QSIG_DIVERT_REASON_UNKNOWN:
					return PRI_REDIR_UNKNOWN;
				case QSIG_DIVERT_REASON_CFU:
					return PRI_REDIR_UNCONDITIONAL;
				case QSIG_DIVERT_REASON_CFB:
					return PRI_REDIR_FORWARD_ON_BUSY;
				case QSIG_DIVERT_REASON_CFNR:
					return PRI_REDIR_FORWARD_ON_NO_REPLY;
				default:
					pri_message(pri, "!! Unknown Q.SIG diversion reason %d\n", redirectingreason);
					return PRI_REDIR_UNKNOWN;
			}
		default:
			switch(redirectingreason) {
				case Q952_DIVERT_REASON_UNKNOWN:
					return PRI_REDIR_UNKNOWN;
				case Q952_DIVERT_REASON_CFU:
					return PRI_REDIR_UNCONDITIONAL;
				case Q952_DIVERT_REASON_CFB:
					return PRI_REDIR_FORWARD_ON_BUSY;
				case Q952_DIVERT_REASON_CFNR:
					return PRI_REDIR_FORWARD_ON_NO_REPLY;
				case Q952_DIVERT_REASON_CD:
					return PRI_REDIR_DEFLECTION;
				case Q952_DIVERT_REASON_IMMEDIATE:
					pri_message(pri, "!! Dont' know how to convert Q.952 diversion reason IMMEDIATE to PRI analog\n");
					return PRI_REDIR_UNKNOWN;	/* ??? */
				default:
					pri_message(pri, "!! Unknown Q.952 diversion reason %d\n", redirectingreason);
					return PRI_REDIR_UNKNOWN;
			}
	}
}
static int rose_presented_number_unscreened_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
{
	int i = 0;
	int size = 0;
	struct rose_component *comp = NULL;
	unsigned char *vdata = data;

	/* Fill in default values */
	value->ton = PRI_TON_UNKNOWN;
	value->npi = PRI_NPI_E163_E164;
	value->pres = -1;	/* Data is not available */

	do {
		GET_COMPONENT(comp, i, vdata, len);

		switch(comp->type) {
		case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0):		/* [0] presentationAllowedNumber */
			value->pres = PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
			size = rose_address_decode(pri, call, comp->data, comp->len, value);
			ASN1_FIXUP_LEN(comp, size);
			return size + 2;
		case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1):		/* [1] IMPLICIT presentationRestricted */
			if (comp->len != 0) { /* must be NULL */
				pri_error(pri, "!! Invalid PresentationRestricted component received (len != 0)\n");
				return -1;
			}
			value->pres = PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
			return 2;
		case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2):		/* [2] IMPLICIT numberNotAvailableDueToInterworking */
			if (comp->len != 0) { /* must be NULL */
				pri_error(pri, "!! Invalid NumberNotAvailableDueToInterworking component received (len != 0)\n");
				return -1;
			}
			value->pres = PRES_NUMBER_NOT_AVAILABLE;
			return 2;
		case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3):		/* [3] presentationRestrictedNumber */
			value->pres = PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
			size = rose_address_decode(pri, call, comp->data, comp->len, value) + 2;
			ASN1_FIXUP_LEN(comp, size);
			return size + 2;
		default:
			pri_message(pri, "Invalid PresentedNumberUnscreened component 0x%X\n", comp->type);
		}
		return -1;
	}
	while (0);

	return -1;
}
/*!
 * \internal
 * \brief Decode the User PartySubaddress argument parameters.
 *
 * \param ctrl D channel controller for any diagnostic messages.
 * \param name Field name
 * \param tag Component tag that identified this production.
 * \param pos Starting position of the ASN.1 component length.
 * \param end End of ASN.1 decoding data buffer.
 * \param party_subaddress Parameter storage to fill.
 *
 * \retval Start of the next ASN.1 component on success.
 * \retval NULL on error.
 */
static const unsigned char *rose_dec_UserSubaddress(struct pri *ctrl, const char *name,
	unsigned tag, const unsigned char *pos, const unsigned char *end,
	struct rosePartySubaddress *party_subaddress)
{
	size_t str_len;
	int32_t odd_count;
	int length;
	int seq_offset;
	const unsigned char *seq_end;

	party_subaddress->type = 0;	/* UserSpecified */

	if (ctrl->debug & PRI_DEBUG_APDU) {
		pri_message(ctrl, "  %s UserSpecified %s\n", name, asn1_tag2str(tag));
	}
	ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
	ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);

	/* SubaddressInformation */
	ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
	ASN1_CHECK_TAG(ctrl, tag, tag & ~ASN1_PC_MASK, ASN1_TYPE_OCTET_STRING);
	ASN1_CALL(pos, asn1_dec_string_bin(ctrl, "subaddressInformation", tag, pos, seq_end,
		sizeof(party_subaddress->u.user_specified.information),
		party_subaddress->u.user_specified.information, &str_len));
	party_subaddress->length = str_len;

	if (pos < seq_end && *pos != ASN1_INDEF_TERM) {
		/*
		 * The optional odd count indicator must be present since there
		 * is something left.
		 */
		ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
		ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_BOOLEAN);
		ASN1_CALL(pos, asn1_dec_boolean(ctrl, "oddCount", tag, pos, seq_end,
			&odd_count));
		party_subaddress->u.user_specified.odd_count = odd_count;
		party_subaddress->u.user_specified.odd_count_present = 1;
	} else {
		party_subaddress->u.user_specified.odd_count = 0;
		party_subaddress->u.user_specified.odd_count_present = 0;
	}

	ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);

	return pos;
}
static int typeofnumber_for_q931(struct pri *pri, int ton)
{
	switch (ton) {
		case Q932_TON_UNKNOWN:
			return PRI_TON_UNKNOWN;
		case Q932_TON_INTERNATIONAL:
			return PRI_TON_INTERNATIONAL;
		case Q932_TON_NATIONAL:
			return PRI_TON_NATIONAL;
		case Q932_TON_NET_SPECIFIC:
			return PRI_TON_NET_SPECIFIC;
		case Q932_TON_SUBSCRIBER:
			return PRI_TON_SUBSCRIBER;
		case Q932_TON_ABBREVIATED:
			return PRI_TON_ABBREVIATED;
		default:
			pri_message(pri, "!! Invalid Q.932 TypeOfNumber %d\n", ton);
			return PRI_TON_UNKNOWN;
	}
}
int typeofnumber_from_q931(struct pri *pri, int ton)
{
	switch(ton) {
		case PRI_TON_INTERNATIONAL:
			return Q932_TON_INTERNATIONAL;
		case PRI_TON_NATIONAL:
			return Q932_TON_NATIONAL;
		case PRI_TON_NET_SPECIFIC:
			return Q932_TON_NET_SPECIFIC;
		case PRI_TON_SUBSCRIBER:
			return Q932_TON_SUBSCRIBER;
		case PRI_TON_ABBREVIATED:
			return Q932_TON_ABBREVIATED;
		case PRI_TON_RESERVED:
		default:
			pri_message(pri, "!! Unsupported Q.931 TypeOfNumber value (%d)\n", ton);
			/* fall through */
		case PRI_TON_UNKNOWN:
			return Q932_TON_UNKNOWN;
	}
}
static void dump_apdu(struct pri *pri, unsigned char *c, int len) 
{
	#define MAX_APDU_LENGTH	255
	int i;
	char message[(2 + MAX_APDU_LENGTH * 3 + 6 + MAX_APDU_LENGTH + 3)] = "";	/* please adjust here, if you make changes below! */
	
	if (len > MAX_APDU_LENGTH)
		return;
	
	snprintf(message, sizeof(message)-1, " [");	
	for (i=0; i<len; i++)
		snprintf((char *)(message+strlen(message)), sizeof(message)-strlen(message)-1, " %02x", c[i]);
	snprintf((char *)(message+strlen(message)), sizeof(message)-strlen(message)-1, " ] - [");
	for (i=0; i<len; i++) {
		if (c[i] < 20 || c[i] >= 128)
			snprintf((char *)(message+strlen(message)), sizeof(message)-strlen(message)-1, "°");
		else
			snprintf((char *)(message+strlen(message)), sizeof(message)-strlen(message)-1, "%c", c[i]);
	}
	snprintf((char *)(message+strlen(message)), sizeof(message)-strlen(message)-1, "]\n");
	pri_message(pri, message);
}
/*!
 * \brief Decode the AddressScreened argument parameters.
 *
 * \param ctrl D channel controller for any diagnostic messages.
 * \param name Field name
 * \param tag Component tag that identified this production.
 * \param pos Starting position of the ASN.1 component length.
 * \param end End of ASN.1 decoding data buffer.
 * \param screened Parameter storage to fill.
 *
 * \retval Start of the next ASN.1 component on success.
 * \retval NULL on error.
 */
const unsigned char *rose_dec_AddressScreened(struct pri *ctrl, const char *name,
	unsigned tag, const unsigned char *pos, const unsigned char *end,
	struct roseAddressScreened *screened)
{
	int32_t value;
	int length;
	int seq_offset;
	const unsigned char *seq_end;

	if (ctrl->debug & PRI_DEBUG_APDU) {
		pri_message(ctrl, "  %s AddressScreened %s\n", name, asn1_tag2str(tag));
	}
	ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
	ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);

	ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
	ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "partyNumber", tag, pos, seq_end,
		&screened->number));

	ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
	ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
	ASN1_CALL(pos, asn1_dec_int(ctrl, "screeningIndicator", tag, pos, seq_end, &value));
	screened->screening_indicator = value;

	if (pos < seq_end && *pos != ASN1_INDEF_TERM) {
		/* The optional subaddress must be present since there is something left. */
		ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
		ASN1_CALL(pos, rose_dec_PartySubaddress(ctrl, "partySubaddress", tag, pos,
			seq_end, &screened->subaddress));
	} else {
		screened->subaddress.length = 0;	/* Subaddress not present */
	}

	ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);

	return pos;
}
Example #20
0
int pri_mwi_deactivate(struct pri *pri, q931_call *c, char *caller, int callerplan, char *callername, int callerpres, char *called,
					int calledplan)
{
	struct pri_sr req;
	if (!pri || !c)
		return -1;

	pri_sr_init(&req);
	pri_sr_set_connection_call_independent(&req);

	req.caller = caller;
	req.callerplan = callerplan;
	req.callername = callername;
	req.callerpres = callerpres;
	req.called = called;
	req.calledplan = calledplan;

	if(mwi_message_send(pri, c, &req, 0) < 0) {
		pri_message(pri, "Unable to send MWI deactivate message\n");
		return -1;
	}

	return q931_setup(pri, c, &req);
}
Example #21
0
/* Don't call any other pri functions on this */
int pri_mwi_activate(struct pri *pri, q931_call *c, char *caller, int callerplan, char *callername, int callerpres, char *called,
					int calledplan)
{
	struct pri_sr req;
	if (!pri || !c)
		return -1;

	pri_sr_init(&req);
	pri_sr_set_connection_call_independent(&req);

	req.caller = caller;
	req.callerplan = callerplan;
	req.callername = callername;
	req.callerpres = callerpres;
	req.called = called;
	req.calledplan = calledplan;

	if (mwi_message_send(pri, c, &req, 1) < 0) {
		pri_message(pri, "Unable to send MWI activate message\n");
		return -1;
	}
	/* Do more stuff when we figure out that the CISC stuff works */
	return q931_setup(pri, c, &req);
}
/*!
 * \brief Decode the PartySubaddress argument parameters.
 *
 * \param ctrl D channel controller for any diagnostic messages.
 * \param name Field name
 * \param tag Component tag that identified this production.
 * \param pos Starting position of the ASN.1 component length.
 * \param end End of ASN.1 decoding data buffer.
 * \param party_subaddress Parameter storage to fill.
 *
 * \retval Start of the next ASN.1 component on success.
 * \retval NULL on error.
 */
const unsigned char *rose_dec_PartySubaddress(struct pri *ctrl, const char *name,
	unsigned tag, const unsigned char *pos, const unsigned char *end,
	struct rosePartySubaddress *party_subaddress)
{
	if (ctrl->debug & PRI_DEBUG_APDU) {
		pri_message(ctrl, "  %s PartySubaddress\n", name);
	}
	switch (tag) {
	case ASN1_TAG_SEQUENCE:
		ASN1_CALL(pos, rose_dec_UserSubaddress(ctrl, "user", tag, pos, end,
			party_subaddress));
		break;
	case ASN1_TYPE_OCTET_STRING:
	case ASN1_TYPE_OCTET_STRING | ASN1_PC_CONSTRUCTED:
		ASN1_CALL(pos, rose_dec_NSAPSubaddress(ctrl, "nsap", tag, pos, end,
			party_subaddress));
		break;
	default:
		ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
		return NULL;
	}

	return pos;
}
/*!
 * \brief Decode the MWIIndicate invoke argument parameters.
 *
 * \param ctrl D channel controller for diagnostic messages or global options.
 * \param tag Component tag that identified this structure.
 * \param pos Starting position of the ASN.1 component length.
 * \param end End of ASN.1 decoding data buffer.
 * \param args Arguments to fill in from the decoded buffer.
 *
 * \retval Start of the next ASN.1 component on success.
 * \retval NULL on error.
 */
const unsigned char *rose_dec_etsi_MWIIndicate_ARG(struct pri *ctrl, unsigned tag,
	const unsigned char *pos, const unsigned char *end,
	union rose_msg_invoke_args *args)
{
	int32_t value;
	size_t str_len;
	int length;
	int seq_offset;
	int explicit_offset;
	const unsigned char *explicit_end;
	const unsigned char *seq_end;
	const unsigned char *save_pos;
	struct roseEtsiMWIIndicate_ARG *mwi_indicate;

	mwi_indicate = &args->etsi.MWIIndicate;

	ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
	if (ctrl->debug & PRI_DEBUG_APDU) {
		pri_message(ctrl, "  MWIIndicate %s\n", asn1_tag2str(tag));
	}
	ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
	ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);

	/*
	 * A sequence specifies an ordered list of component types.
	 * However, for simplicity we are not checking the order of
	 * the remaining optional components.
	 */
	mwi_indicate->controlling_user_number.length = 0;
	mwi_indicate->basic_service_present = 0;
	mwi_indicate->number_of_messages_present = 0;
	mwi_indicate->controlling_user_provided_number.length = 0;
	mwi_indicate->time_present = 0;
	mwi_indicate->message_id_present = 0;
	while (pos < seq_end && *pos != ASN1_INDEF_TERM) {
		save_pos = pos;
		ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
		switch (tag) {
		case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1:
			/* Remove EXPLICIT tag */
			if (ctrl->debug & PRI_DEBUG_APDU) {
				pri_message(ctrl, "  Explicit %s\n", asn1_tag2str(tag));
			}
			ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
			ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);

			ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
			ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "controllingUserNr", tag, pos,
				explicit_end, &mwi_indicate->controlling_user_number));

			ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
			break;
		case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2:
			/* Remove EXPLICIT tag */
			if (ctrl->debug & PRI_DEBUG_APDU) {
				pri_message(ctrl, "  Explicit %s\n", asn1_tag2str(tag));
			}
			ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
			ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);

			ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
			ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
			ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, explicit_end,
				&value));
			mwi_indicate->basic_service = value;
			mwi_indicate->basic_service_present = 1;

			ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
			break;
		case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 3:
			/* Remove EXPLICIT tag */
			if (ctrl->debug & PRI_DEBUG_APDU) {
				pri_message(ctrl, "  Explicit %s\n", asn1_tag2str(tag));
			}
			ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
			ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);

			ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
			ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_INTEGER);
			ASN1_CALL(pos, asn1_dec_int(ctrl, "numberOfMessages", tag, pos, explicit_end,
				&value));
			mwi_indicate->number_of_messages = value;
			mwi_indicate->number_of_messages_present = 1;

			ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
			break;
		case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 4:
			/* Remove EXPLICIT tag */
			if (ctrl->debug & PRI_DEBUG_APDU) {
				pri_message(ctrl, "  Explicit %s\n", asn1_tag2str(tag));
			}
			ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
			ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);

			ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
			ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "controllingUserProvidedNr", tag,
				pos, explicit_end, &mwi_indicate->controlling_user_provided_number));

			ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
			break;
		case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 5:
			/* Remove EXPLICIT tag */
			if (ctrl->debug & PRI_DEBUG_APDU) {
				pri_message(ctrl, "  Explicit %s\n", asn1_tag2str(tag));
			}
			ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
			ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);

			ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
			ASN1_CHECK_TAG(ctrl, tag & ~ASN1_PC_MASK, tag, ASN1_TYPE_GENERALIZED_TIME);
			ASN1_CALL(pos, asn1_dec_string_max(ctrl, "time", tag, pos, explicit_end,
				sizeof(mwi_indicate->time.str), mwi_indicate->time.str, &str_len));
			mwi_indicate->time_present = 1;

			ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
			break;
		case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 6:
			/* Remove EXPLICIT tag */
			if (ctrl->debug & PRI_DEBUG_APDU) {
				pri_message(ctrl, "  Explicit %s\n", asn1_tag2str(tag));
			}
			ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
			ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);

			ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
			ASN1_CALL(pos, rose_dec_etsi_message_id(ctrl, "messageId", tag, pos,
				explicit_end, &mwi_indicate->message_id));
			mwi_indicate->message_id_present = 1;

			ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
			break;
		default:
			pos = save_pos;
			goto cancel_options;
		}
	}
cancel_options:;

	ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);

	return pos;
}
static int rose_diverting_leg_information2_encode(struct pri *pri, q931_call *call)
{
	int i = 0, j, compsp = 0;
	struct rose_component *comp, *compstk[10];
	unsigned char buffer[256];
	int len = 253;
	
	if (!strlen(call->callername)) {
		return -1;
	}

	buffer[i] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
	i++;
	/* Interpretation component */
	ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0x00 /* Discard unrecognized invokes */);
	
	ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
	
	ASN1_PUSH(compstk, compsp, comp);
	/* Invoke component contents */
	/*	Invoke ID */
	ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri));
	/*	Operation Tag */
	
	/* ROSE operationId component */
	ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, ROSE_DIVERTING_LEG_INFORMATION2);

	/* ROSE ARGUMENT component */
	ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
	ASN1_PUSH(compstk, compsp, comp);
	/* ROSE DivertingLegInformation2.diversionCounter component */
	/* Always is 1 because other isn't available in the current design */
	ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, 1);
	
	/* ROSE DivertingLegInformation2.diversionReason component */
	ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, redirectingreason_from_q931(pri, call->redirectingreason));
		
	/* ROSE DivertingLegInformation2.divertingNr component */
	ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i);
	
	ASN1_PUSH(compstk, compsp, comp);
		/* Redirecting information always not screened */
	
	switch(call->redirectingpres) {
		case PRES_ALLOWED_USER_NUMBER_NOT_SCREENED:
		case PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN:
			if (call->redirectingnum && strlen(call->redirectingnum)) {
				ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0), buffer, i);
				ASN1_PUSH(compstk, compsp, comp);
					/* NPI of redirected number is not supported in the current design */
				ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i);
				ASN1_PUSH(compstk, compsp, comp);
					ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, typeofnumber_from_q931(pri, call->redirectingplan >> 4));
					j = asn1_string_encode(ASN1_NUMERICSTRING, &buffer[i], len - i, 20, call->redirectingnum, strlen(call->redirectingnum));
				if (j < 0)
					return -1;
					
				i += j;
				ASN1_FIXUP(compstk, compsp, buffer, i);
				ASN1_FIXUP(compstk, compsp, buffer, i);
				break;
			}
			/* fall through */
		case PRES_PROHIB_USER_NUMBER_PASSED_SCREEN:
		case PRES_PROHIB_USER_NUMBER_NOT_SCREENED:
			ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), buffer, i);
			break;
		/* Don't know how to handle this */
		case PRES_ALLOWED_NETWORK_NUMBER:
		case PRES_PROHIB_NETWORK_NUMBER:
		case PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN:
		case PRES_PROHIB_USER_NUMBER_FAILED_SCREEN:
			ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), buffer, i);
			break;
		default:
			pri_message(pri, "!! Undefined presentation value for redirecting number: %d\n", call->redirectingpres);
		case PRES_NUMBER_NOT_AVAILABLE:
			ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i);
			break;
	}
static int rose_diverting_leg_information2_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len)
{
	int i = 0;
	int diversion_counter;
	int diversion_reason;
	char origcalledname[50] = "", redirectingname[50] = "";
	struct addressingdataelements_presentednumberunscreened divertingnr;
 	struct addressingdataelements_presentednumberunscreened originalcallednr;
	struct rose_component *comp = NULL;
	unsigned char *vdata = sequence->data;
	int res = 0;

	/* Data checks */
	if (sequence->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */
		pri_message(pri, "Invalid DivertingLegInformation2Type argument\n");
		return -1;
	}

	if (sequence->len == ASN1_LEN_INDEF) {
		len -= 4; /* For the 2 extra characters at the end
                           * and two characters of header */
	} else
		len -= 2;

	do {
		/* diversionCounter stuff */
		GET_COMPONENT(comp, i, vdata, len);
		CHECK_COMPONENT(comp, ASN1_INTEGER, "Don't know what to do it diversionCounter is of type 0x%x\n");
		ASN1_GET_INTEGER(comp, diversion_counter);
		NEXT_COMPONENT(comp, i);

		/* diversionReason stuff */
		GET_COMPONENT(comp, i, vdata, len);
		CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Invalid diversionReason type 0x%X of ROSE divertingLegInformation2 component received\n");
		ASN1_GET_INTEGER(comp, diversion_reason);
		NEXT_COMPONENT(comp, i);

		diversion_reason = redirectingreason_for_q931(pri, diversion_reason);
	
		if(pri->debug & PRI_DEBUG_APDU)
			pri_message(pri, "    Redirection reason: %d, total diversions: %d\n", diversion_reason, diversion_counter);
		pri_message(NULL, "Length of message is %d\n", len);

		for(; i < len; NEXT_COMPONENT(comp, i)) {
			GET_COMPONENT(comp, i, vdata, len);
			switch(comp->type) {
			case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0):
				call->origredirectingreason = redirectingreason_for_q931(pri, comp->data[0]);
				if (pri->debug & PRI_DEBUG_APDU)
					pri_message(pri, "    Received reason for original redirection %d\n", call->origredirectingreason);
				break;
			case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1):
				res = rose_presented_number_unscreened_decode(pri, call, comp->data, comp->len, &divertingnr);
				/* TODO: Fix indefinite length form hacks */
				ASN1_FIXUP_LEN(comp, res);
				comp->len = res;
				if (res < 0)
					return -1;
				if (pri->debug & PRI_DEBUG_APDU) {
					pri_message(pri, "    Received divertingNr '%s'\n", divertingnr.partyaddress);
					pri_message(pri, "      ton = %d, pres = %d, npi = %d\n", divertingnr.ton, divertingnr.pres, divertingnr.npi);
				}
				break;
			case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_2):
				res = rose_presented_number_unscreened_decode(pri, call, comp->data, comp->len, &originalcallednr);
				if (res < 0)
					return -1;
				ASN1_FIXUP_LEN(comp, res);
				comp->len = res;
				if (pri->debug & PRI_DEBUG_APDU) {
					pri_message(pri, "    Received originalcallednr '%s'\n", originalcallednr.partyaddress);
					pri_message(pri, "      ton = %d, pres = %d, npi = %d\n", originalcallednr.ton, originalcallednr.pres, originalcallednr.npi);
				}
				break;
			case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3):
				res = asn1_name_decode(comp->data, comp->len, redirectingname, sizeof(redirectingname));
				if (res < 0)
					return -1;
				ASN1_FIXUP_LEN(comp, res);
				comp->len = res;
				if (pri->debug & PRI_DEBUG_APDU)
					pri_message(pri, "    Received RedirectingName '%s'\n", redirectingname);
				break;
			case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_4):
				res = asn1_name_decode(comp->data, comp->len, origcalledname, sizeof(origcalledname));
				if (res < 0)
					return -1;
				ASN1_FIXUP_LEN(comp, res);
				comp->len = res;
				if (pri->debug & PRI_DEBUG_APDU)
					pri_message(pri, "    Received Originally Called Name '%s'\n", origcalledname);
				break;
			default:
				if (comp->type == 0 && comp->len == 0) {
					break; /* Found termination characters */
				}
				pri_message(pri, "!! Invalid DivertingLegInformation2 component received 0x%X\n", comp->type);
				return -1;
			}
		}

		if (divertingnr.pres >= 0) {
			call->redirectingplan = divertingnr.npi;
			call->redirectingpres = divertingnr.pres;
			call->redirectingreason = diversion_reason;
			libpri_copy_string(call->redirectingnum, divertingnr.partyaddress, sizeof(call->redirectingnum));
		}
		if (originalcallednr.pres >= 0) {
			call->origcalledplan = originalcallednr.npi;
			call->origcalledpres = originalcallednr.pres;
			libpri_copy_string(call->origcallednum, originalcallednr.partyaddress, sizeof(call->origcallednum));
		}
		libpri_copy_string(call->redirectingname, redirectingname, sizeof(call->redirectingname));
		libpri_copy_string(call->origcalledname, origcalledname, sizeof(call->origcalledname));
		return 0;
	}
	while (0);

	return -1;
}
static int rose_address_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
{
	int i = 0;
	struct rose_component *comp = NULL;
	unsigned char *vdata = data;
	int res = 0;

	do {
		GET_COMPONENT(comp, i, vdata, len);

		switch(comp->type) {
		case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0):	/* [0] unknownPartyNumber */
			res = rose_number_digits_decode(pri, call, comp->data, comp->len, value);
			if (res < 0)
				return -1;
			value->npi = PRI_NPI_UNKNOWN;
			value->ton = PRI_TON_UNKNOWN;
			break;
		case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0):	/* [0] unknownPartyNumber */
			res = asn1_copy_string(value->partyaddress, sizeof(value->partyaddress), comp);
			if (res < 0)
				return -1;
			value->npi = PRI_NPI_UNKNOWN;
			value->ton = PRI_TON_UNKNOWN;
			break;
		case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1):	/* [1] publicPartyNumber */
			res = rose_public_party_number_decode(pri, call, comp->data, comp->len, value);
			if (res < 0)
				return -1;
			value->npi = PRI_NPI_E163_E164;
			break;
		case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_2):	/* [2] nsapEncodedNumber */
			pri_message(pri, "!! NsapEncodedNumber isn't handled\n");
			return -1;
		case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3):	/* [3] dataPartyNumber */
			if(rose_number_digits_decode(pri, call, comp->data, comp->len, value))
				return -1;
			value->npi = PRI_NPI_X121 /* ??? */;
			value->ton = PRI_TON_UNKNOWN /* ??? */;
			pri_message(pri, "!! dataPartyNumber isn't handled\n");
			return -1;
		case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_4):	/* [4] telexPartyNumber */
			res = rose_number_digits_decode(pri, call, comp->data, comp->len, value);
			if (res < 0)
				return -1;
			value->npi = PRI_NPI_F69 /* ??? */;
			value->ton = PRI_TON_UNKNOWN /* ??? */;
			pri_message(pri, "!! telexPartyNumber isn't handled\n");
			return -1;
		case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_5):	/* [5] priavePartyNumber */
			pri_message(pri, "!! privatePartyNumber isn't handled\n");
			value->npi = PRI_NPI_PRIVATE;
			return -1;
		case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_8):	/* [8] nationalStandardPartyNumber */
			res = rose_number_digits_decode(pri, call, comp->data, comp->len, value);
			if (res < 0)
				return -1;
			value->npi = PRI_NPI_NATIONAL;
			value->ton = PRI_TON_NATIONAL;
			break;
		default:
			pri_message(pri, "!! Unknown Party number component received 0x%X\n", comp->type);
			return -1;
		}
		ASN1_FIXUP_LEN(comp, res);
		NEXT_COMPONENT(comp, i);
		if(i < len)
			pri_message(pri, "!! not all information is handled from Address component\n");
		return res + 2;
	}
	while (0);

	return -1;
}