You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libpri/rose_address.c

984 lines
33 KiB

/*
* libpri: An implementation of Primary Rate ISDN
*
* Copyright (C) 2009 Digium, Inc.
*
* Richard Mudgett <rmudgett@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2 as published by the
* Free Software Foundation. See the LICENSE file included with
* this program for more details.
*
* In addition, when this program is distributed with Asterisk in
* any form that would qualify as a 'combined work' or as a
* 'derivative work' (but not mere aggregation), you can redistribute
* and/or modify the combination under the terms of the license
* provided with that copy of Asterisk, instead of the license
* terms granted here.
*/
/*!
* \file
* \brief ROSE Addressing-Data-Elements
*
* Addressing-Data-Elements ETS 300 196-1 D.3
*
* \author Richard Mudgett <rmudgett@digium.com>
*/
#include "compat.h"
#include "libpri.h"
#include "pri_internal.h"
#include "rose.h"
#include "rose_internal.h"
#include "asn1.h"
/* ------------------------------------------------------------------- */
/*!
* \internal
* \brief Encode the public or private network PartyNumber type.
*
* \param ctrl D channel controller for diagnostic messages or global options.
* \param pos Starting position to encode ASN.1 component.
* \param end End of ASN.1 encoding data buffer.
* \param tag Component tag to identify the encoded component.
* The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly
* tags it otherwise.
* \param number
* \param length_of_number
* \param type_of_number
*
* \retval Start of the next ASN.1 component to encode on success.
* \retval NULL on error.
*/
static unsigned char *rose_enc_NetworkPartyNumber(struct pri *ctrl, unsigned char *pos,
unsigned char *end, unsigned tag, const unsigned char *number,
size_t length_of_number, u_int8_t type_of_number)
{
unsigned char *seq_len;
ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, type_of_number));
ASN1_CALL(pos, asn1_enc_string_bin(pos, end, ASN1_TYPE_NUMERIC_STRING, number,
length_of_number));
ASN1_CONSTRUCTED_END(seq_len, pos, end);
return pos;
}
/*!
* \brief Encode the PartyNumber type.
*
* \param ctrl D channel controller for diagnostic messages or global options.
* \param pos Starting position to encode ASN.1 component.
* \param end End of ASN.1 encoding data buffer.
* \param party_number
*
* \retval Start of the next ASN.1 component to encode on success.
* \retval NULL on error.
*/
unsigned char *rose_enc_PartyNumber(struct pri *ctrl, unsigned char *pos,
unsigned char *end, const struct rosePartyNumber *party_number)
{
switch (party_number->plan) {
case 0: /* Unknown PartyNumber */
ASN1_CALL(pos, asn1_enc_string_bin(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 0,
party_number->str, party_number->length));
break;
case 1: /* Public PartyNumber */
ASN1_CALL(pos, rose_enc_NetworkPartyNumber(ctrl, pos, end,
ASN1_CLASS_CONTEXT_SPECIFIC | 1, party_number->str, party_number->length,
party_number->ton));
break;
case 2: /* NSAP encoded PartyNumber */
ASN1_CALL(pos, asn1_enc_string_bin(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2,
party_number->str, party_number->length));
break;
case 3: /* Data PartyNumber (Not used) */
ASN1_CALL(pos, asn1_enc_string_bin(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 3,
party_number->str, party_number->length));
break;
case 4: /* Telex PartyNumber (Not used) */
ASN1_CALL(pos, asn1_enc_string_bin(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 4,
party_number->str, party_number->length));
break;
case 5: /* Private PartyNumber */
ASN1_CALL(pos, rose_enc_NetworkPartyNumber(ctrl, pos, end,
ASN1_CLASS_CONTEXT_SPECIFIC | 5, party_number->str, party_number->length,
party_number->ton));
break;
case 8: /* National Standard PartyNumber (Not used) */
ASN1_CALL(pos, asn1_enc_string_bin(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 8,
party_number->str, party_number->length));
break;
default:
ASN1_ENC_ERROR(ctrl, "Unknown numbering plan");
return NULL;
}
return pos;
}
/*!
* \brief Encode the PartySubaddress type.
*
* \param ctrl D channel controller for diagnostic messages or global options.
* \param pos Starting position to encode ASN.1 component.
* \param end End of ASN.1 encoding data buffer.
* \param party_subaddress
*
* \retval Start of the next ASN.1 component to encode on success.
* \retval NULL on error.
*/
unsigned char *rose_enc_PartySubaddress(struct pri *ctrl, unsigned char *pos,
unsigned char *end, const struct rosePartySubaddress *party_subaddress)
{
unsigned char *seq_len;
switch (party_subaddress->type) {
case 0: /* UserSpecified */
ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
ASN1_CALL(pos, asn1_enc_string_bin(pos, end, ASN1_TYPE_OCTET_STRING,
party_subaddress->u.user_specified.information, party_subaddress->length));
if (party_subaddress->u.user_specified.odd_count_present) {
ASN1_CALL(pos, asn1_enc_boolean(pos, end, ASN1_TYPE_BOOLEAN,
party_subaddress->u.user_specified.odd_count));
}
ASN1_CONSTRUCTED_END(seq_len, pos, end);
break;
case 1: /* NSAP */
ASN1_CALL(pos, asn1_enc_string_bin(pos, end, ASN1_TYPE_OCTET_STRING,
party_subaddress->u.nsap, party_subaddress->length));
break;
default:
ASN1_ENC_ERROR(ctrl, "Unknown subaddress type");
return NULL;
}
return pos;
}
/*!
* \brief Encode the Address type.
*
* \param ctrl D channel controller for diagnostic messages or global options.
* \param pos Starting position to encode ASN.1 component.
* \param end End of ASN.1 encoding data buffer.
* \param tag Component tag to identify the encoded component.
* The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly
* tags it otherwise.
* \param address
*
* \retval Start of the next ASN.1 component to encode on success.
* \retval NULL on error.
*/
unsigned char *rose_enc_Address(struct pri *ctrl, unsigned char *pos, unsigned char *end,
unsigned tag, const struct roseAddress *address)
{
unsigned char *seq_len;
ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, &address->number));
if (address->subaddress.length) {
ASN1_CALL(pos, rose_enc_PartySubaddress(ctrl, pos, end, &address->subaddress));
}
ASN1_CONSTRUCTED_END(seq_len, pos, end);
return pos;
}
/*!
* \brief Encode the PresentedNumberUnscreened type.
*
* \param ctrl D channel controller for diagnostic messages or global options.
* \param pos Starting position to encode ASN.1 component.
* \param end End of ASN.1 encoding data buffer.
* \param party
*
* \retval Start of the next ASN.1 component to encode on success.
* \retval NULL on error.
*/
unsigned char *rose_enc_PresentedNumberUnscreened(struct pri *ctrl, unsigned char *pos,
unsigned char *end, const struct rosePresentedNumberUnscreened *party)
{
unsigned char *seq_len;
switch (party->presentation) {
case 0: /* presentationAllowedNumber */
/* EXPLICIT tag */
ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 0);
ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, &party->number));
ASN1_CONSTRUCTED_END(seq_len, pos, end);
break;
case 1: /* presentationRestricted */
ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1));
break;
case 2: /* numberNotAvailableDueToInterworking */
ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2));
break;
case 3: /* presentationRestrictedNumber */
/* EXPLICIT tag */
ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 3);
ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, &party->number));
ASN1_CONSTRUCTED_END(seq_len, pos, end);
break;
default:
ASN1_ENC_ERROR(ctrl, "Unknown presentation type");
return NULL;
}
return pos;
}
/*!
* \brief Encode the NumberScreened type.
*
* \param ctrl D channel controller for diagnostic messages or global options.
* \param pos Starting position to encode ASN.1 component.
* \param end End of ASN.1 encoding data buffer.
* \param tag Component tag to identify the encoded component.
* The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly
* tags it otherwise.
* \param screened
*
* \retval Start of the next ASN.1 component to encode on success.
* \retval NULL on error.
*/
unsigned char *rose_enc_NumberScreened(struct pri *ctrl, unsigned char *pos,
unsigned char *end, unsigned tag, const struct roseNumberScreened *screened)
{
unsigned char *seq_len;
ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, &screened->number));
ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
screened->screening_indicator));
ASN1_CONSTRUCTED_END(seq_len, pos, end);
return pos;
}
/*!
* \brief Encode the PresentedNumberScreened type.
*
* \param ctrl D channel controller for diagnostic messages or global options.
* \param pos Starting position to encode ASN.1 component.
* \param end End of ASN.1 encoding data buffer.
* \param party
*
* \retval Start of the next ASN.1 component to encode on success.
* \retval NULL on error.
*/
unsigned char *rose_enc_PresentedNumberScreened(struct pri *ctrl, unsigned char *pos,
unsigned char *end, const struct rosePresentedNumberScreened *party)
{
switch (party->presentation) {
case 0: /* presentationAllowedNumber */
ASN1_CALL(pos, rose_enc_NumberScreened(ctrl, pos, end,
ASN1_CLASS_CONTEXT_SPECIFIC | 0, &party->screened));
break;
case 1: /* presentationRestricted */
ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1));
break;
case 2: /* numberNotAvailableDueToInterworking */
ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2));
break;
case 3: /* presentationRestrictedNumber */
ASN1_CALL(pos, rose_enc_NumberScreened(ctrl, pos, end,
ASN1_CLASS_CONTEXT_SPECIFIC | 3, &party->screened));
break;
default:
ASN1_ENC_ERROR(ctrl, "Unknown presentation type");
return NULL;
}
return pos;
}
/*!
* \brief Encode the AddressScreened type.
*
* \param ctrl D channel controller for diagnostic messages or global options.
* \param pos Starting position to encode ASN.1 component.
* \param end End of ASN.1 encoding data buffer.
* \param tag Component tag to identify the encoded component.
* The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly
* tags it otherwise.
* \param screened
*
* \retval Start of the next ASN.1 component to encode on success.
* \retval NULL on error.
*/
unsigned char *rose_enc_AddressScreened(struct pri *ctrl, unsigned char *pos,
unsigned char *end, unsigned tag, const struct roseAddressScreened *screened)
{
unsigned char *seq_len;
ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, &screened->number));
ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
screened->screening_indicator));
if (screened->subaddress.length) {
ASN1_CALL(pos, rose_enc_PartySubaddress(ctrl, pos, end, &screened->subaddress));
}
ASN1_CONSTRUCTED_END(seq_len, pos, end);
return pos;
}
/*!
* \brief Encode the PresentedAddressScreened type.
*
* \param ctrl D channel controller for diagnostic messages or global options.
* \param pos Starting position to encode ASN.1 component.
* \param end End of ASN.1 encoding data buffer.
* \param party
*
* \retval Start of the next ASN.1 component to encode on success.
* \retval NULL on error.
*/
unsigned char *rose_enc_PresentedAddressScreened(struct pri *ctrl, unsigned char *pos,
unsigned char *end, const struct rosePresentedAddressScreened *party)
{
switch (party->presentation) {
case 0: /* presentationAllowedAddress */
ASN1_CALL(pos, rose_enc_AddressScreened(ctrl, pos, end,
ASN1_CLASS_CONTEXT_SPECIFIC | 0, &party->screened));
break;
case 1: /* presentationRestricted */
ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1));
break;
case 2: /* numberNotAvailableDueToInterworking */
ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2));
break;
case 3: /* presentationRestrictedAddress */
ASN1_CALL(pos, rose_enc_AddressScreened(ctrl, pos, end,
ASN1_CLASS_CONTEXT_SPECIFIC | 3, &party->screened));
break;
default:
ASN1_ENC_ERROR(ctrl, "Unknown presentation type");
return NULL;
}
return pos;
}
/*!
* \internal
* \brief Decode the NumberDigits 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_NumberDigits(struct pri *ctrl, const char *name,
unsigned tag, const unsigned char *pos, const unsigned char *end,
struct rosePartyNumber *party_number)
{
size_t str_len;
ASN1_CALL(pos, asn1_dec_string_max(ctrl, name, tag, pos, end,
sizeof(party_number->str), party_number->str, &str_len));
party_number->length = str_len;
return pos;
}
/*!
* \internal
* \brief Decode the NSAP 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_NSAPPartyNumber(struct pri *ctrl, const char *name,
unsigned tag, const unsigned char *pos, const unsigned char *end,
struct rosePartyNumber *party_number)
{
size_t str_len;
ASN1_CALL(pos, asn1_dec_string_bin(ctrl, name, tag, pos, end,
sizeof(party_number->str), party_number->str, &str_len));
party_number->length = str_len;
return pos;
}
/*!
* \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 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;
}
/*!
* \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;
}
/*!
* \internal
* \brief Decode the NSAP 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_NSAPSubaddress(struct pri *ctrl, const char *name,
unsigned tag, const unsigned char *pos, const unsigned char *end,
struct rosePartySubaddress *party_subaddress)
{
size_t str_len;
party_subaddress->type = 1; /* NSAP */
ASN1_CALL(pos, asn1_dec_string_bin(ctrl, name, tag, pos, end,
sizeof(party_subaddress->u.nsap), party_subaddress->u.nsap, &str_len));
party_subaddress->length = str_len;
return pos;
}
/*!
* \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 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;
}
/*!
* \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;
}
/*!
* \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 PresentedNumberScreened 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_PresentedNumberScreened(struct pri *ctrl, const char *name,
unsigned tag, const unsigned char *pos, const unsigned char *end,
struct rosePresentedNumberScreened *party)
{
if (ctrl->debug & PRI_DEBUG_APDU) {
pri_message(ctrl, " %s PresentedNumberScreened\n", name);
}
switch (tag) {
case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 0:
party->presentation = 0; /* presentationAllowedNumber */
ASN1_CALL(pos, rose_dec_NumberScreened(ctrl, "presentationAllowedNumber", 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; /* presentationRestrictedNumber */
ASN1_CALL(pos, rose_dec_NumberScreened(ctrl, "presentationRestrictedNumber", tag,
pos, end, &party->screened));
break;
default:
ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
return NULL;
}
return pos;
}
/*!
* \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;
}
/*!
* \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;
}
/* ------------------------------------------------------------------- */
/* end rose_address.c */