From b19c0b0a0481680bd011b945f0ac5604c8892df7 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 21 Apr 2009 23:32:13 +0000 Subject: [PATCH] Added Q.SIG Advice-Of-Charge encode/decode routines. git-svn-id: https://origsvn.digium.com/svn/libpri/branches/1.4@772 2fbb986a-6c06-0410-b554-c9c1f0a7f128 --- Makefile | 2 + pri_facility.c | 22 + rose.c | 59 ++ rose.h | 473 +++++++++++++ rose_internal.h | 48 +- rose_qsig_aoc.c | 1714 +++++++++++++++++++++++++++++++++++++++++++++++ rosetest.c | 312 +++++++++ 7 files changed, 2628 insertions(+), 2 deletions(-) create mode 100644 rose_qsig_aoc.c diff --git a/Makefile b/Makefile index e2ef8fa..beffe15 100644 --- a/Makefile +++ b/Makefile @@ -54,6 +54,7 @@ STATIC_OBJS= \ rose_etsi_aoc.o \ rose_other.o \ rose_q931.o \ + rose_qsig_aoc.o \ rose_qsig_ct.o \ rose_qsig_diversion.o \ rose_qsig_mwi.o \ @@ -72,6 +73,7 @@ DYNAMIC_OBJS= \ rose_etsi_aoc.lo \ rose_other.lo \ rose_q931.lo \ + rose_qsig_aoc.lo \ rose_qsig_ct.lo \ rose_qsig_diversion.lo \ rose_qsig_mwi.lo \ diff --git a/pri_facility.c b/pri_facility.c index 3b4bea9..f6d09ba 100644 --- a/pri_facility.c +++ b/pri_facility.c @@ -1559,6 +1559,12 @@ void rose_handle_result(struct pri *ctrl, q931_call *call, q931_ie *ie, case ROSE_ETSI_ChargingRequest: break; #endif /* Not handled yet */ +#if 0 /* Not handled yet */ + case ROSE_QSIG_ChargeRequest: + break; + case ROSE_QSIG_AocComplete: + break; +#endif /* Not handled yet */ #if 0 /* Not handled yet */ case ROSE_QSIG_CallTransferIdentify: break; @@ -1673,6 +1679,22 @@ void rose_handle_invoke(struct pri *ctrl, q931_call *call, q931_ie *ie, case ROSE_QSIG_BusyName: break; #endif /* Not handled yet */ +#if 0 /* Not handled yet */ + case ROSE_QSIG_ChargeRequest: + break; + case ROSE_QSIG_GetFinalCharge: + break; + case ROSE_QSIG_AocFinal: + break; + case ROSE_QSIG_AocInterim: + break; + case ROSE_QSIG_AocRate: + break; + case ROSE_QSIG_AocComplete: + break; + case ROSE_QSIG_AocDivChargeReq: + break; +#endif /* Not handled yet */ #if 0 /* Not handled yet */ case ROSE_QSIG_CallTransferIdentify: break; diff --git a/rose.c b/rose.c index 7ee2554..27de736 100644 --- a/rose.c +++ b/rose.c @@ -343,6 +343,46 @@ static const struct rose_convert_msg rose_qsig_msgs[] = { rose_dec_qsig_BusyName_ARG, NULL }, + /* + * localValue's from Q.SIG SS-AOC-Operations + * { iso(1) standard(0) pss1-advice-of-charge(15050) advice-of-charge-operations(0) } + */ + { + ROSE_QSIG_ChargeRequest, NULL, 59, + rose_enc_qsig_ChargeRequest_ARG, rose_enc_qsig_ChargeRequest_RES, + rose_dec_qsig_ChargeRequest_ARG, rose_dec_qsig_ChargeRequest_RES + }, + { + ROSE_QSIG_GetFinalCharge, NULL, 60, + rose_enc_qsig_DummyArg_ARG, NULL, + rose_dec_qsig_DummyArg_ARG, NULL + }, + { + ROSE_QSIG_AocFinal, NULL, 61, + rose_enc_qsig_AocFinal_ARG, NULL, + rose_dec_qsig_AocFinal_ARG, NULL + }, + { + ROSE_QSIG_AocInterim, NULL, 62, + rose_enc_qsig_AocInterim_ARG, NULL, + rose_dec_qsig_AocInterim_ARG, NULL + }, + { + ROSE_QSIG_AocRate, NULL, 63, + rose_enc_qsig_AocRate_ARG, NULL, + rose_dec_qsig_AocRate_ARG, NULL + }, + { + ROSE_QSIG_AocComplete, NULL, 64, + rose_enc_qsig_AocComplete_ARG, rose_enc_qsig_AocComplete_RES, + rose_dec_qsig_AocComplete_ARG, rose_dec_qsig_AocComplete_RES + }, + { + ROSE_QSIG_AocDivChargeReq, NULL, 65, + rose_enc_qsig_AocDivChargeReq_ARG, NULL, + rose_dec_qsig_AocDivChargeReq_ARG, NULL + }, + /* * localValue's from Q.SIG Call-Transfer-Operations * { iso(1) standard(0) pss1-call-transfer(13869) call-transfer-operations(0) } @@ -545,6 +585,15 @@ static const struct rose_convert_error rose_qsig_errors[] = { NULL, NULL }, + /* + * localValue Errors from Q.SIG SS-AOC-Operations + * { iso(1) standard(0) pss1-advice-of-charge(15050) advice-of-charge-operations(0) } + */ + { + ROSE_ERROR_QSIG_AOC_FreeOfCharge, NULL, 1016, + NULL, NULL + }, + /* * localValue's from Q.SIG Call-Transfer-Operations * { iso(1) standard(0) pss1-call-transfer(13869) call-transfer-operations(0) } @@ -844,6 +893,14 @@ const char *rose_operation2str(enum rose_operation operation) { ROSE_QSIG_ConnectedName, "ROSE_QSIG_ConnectedName" }, { ROSE_QSIG_BusyName, "ROSE_QSIG_BusyName" }, + { ROSE_QSIG_ChargeRequest, "ROSE_QSIG_ChargeRequest" }, + { ROSE_QSIG_GetFinalCharge, "ROSE_QSIG_GetFinalCharge" }, + { ROSE_QSIG_AocFinal, "ROSE_QSIG_AocFinal" }, + { ROSE_QSIG_AocInterim, "ROSE_QSIG_AocInterim" }, + { ROSE_QSIG_AocRate, "ROSE_QSIG_AocRate" }, + { ROSE_QSIG_AocComplete, "ROSE_QSIG_AocComplete" }, + { ROSE_QSIG_AocDivChargeReq, "ROSE_QSIG_AocDivChargeReq" }, + { ROSE_QSIG_CallTransferIdentify, "ROSE_QSIG_CallTransferIdentify" }, { ROSE_QSIG_CallTransferAbandon, "ROSE_QSIG_CallTransferAbandon" }, { ROSE_QSIG_CallTransferInitiate, "ROSE_QSIG_CallTransferInitiate" }, @@ -921,6 +978,8 @@ const char *rose_error2str(enum rose_error_code code) /* Q.SIG specific errors */ { ROSE_ERROR_QSIG_Unspecified, "Unspecified" }, + { ROSE_ERROR_QSIG_AOC_FreeOfCharge, "AOC: FreeOfCharge" }, + { ROSE_ERROR_QSIG_CT_InvalidReroutingNumber, "CT: Invalid Rerouting Number" }, { ROSE_ERROR_QSIG_CT_UnrecognizedCallIdentity,"CT: Unrecognized Call Identity" }, { ROSE_ERROR_QSIG_CT_EstablishmentFailure, "CT: Establishment Failure" }, diff --git a/rose.h b/rose.h index bb31259..8c91165 100644 --- a/rose.h +++ b/rose.h @@ -86,6 +86,15 @@ enum rose_operation { ROSE_QSIG_ConnectedName, /*!< Invoke only */ ROSE_QSIG_BusyName, /*!< Invoke only */ + /* Q.SIG SS-AOC-Operations */ + ROSE_QSIG_ChargeRequest, /*!< Invoke/Result */ + ROSE_QSIG_GetFinalCharge, /*!< Invoke only */ + ROSE_QSIG_AocFinal, /*!< Invoke only */ + ROSE_QSIG_AocInterim, /*!< Invoke only */ + ROSE_QSIG_AocRate, /*!< Invoke only */ + ROSE_QSIG_AocComplete, /*!< Invoke/Result */ + ROSE_QSIG_AocDivChargeReq, /*!< Invoke only */ + /* Q.SIG Call-Transfer-Operations (CT) */ ROSE_QSIG_CallTransferIdentify, /*!< Invoke/Result */ ROSE_QSIG_CallTransferAbandon, /*!< Invoke only */ @@ -163,6 +172,9 @@ enum rose_error_code { /* Q.SIG from various specifications */ ROSE_ERROR_QSIG_Unspecified, + /* Q.SIG SS-AOC-Operations */ + ROSE_ERROR_QSIG_AOC_FreeOfCharge, + /* Q.SIG Call-Transfer-Operations (CT) */ ROSE_ERROR_QSIG_CT_InvalidReroutingNumber, ROSE_ERROR_QSIG_CT_UnrecognizedCallIdentity, @@ -1122,6 +1134,455 @@ struct roseQsigPartyName_ARG { /* ------------------------------------------------------------------- */ +/* + * Time ::= SEQUENCE { + * lengthOfTimeUnit [1] IMPLICIT LengthOfTimeUnit, + * scale [2] IMPLICIT Scale + * } + */ +struct roseQsigAOCTime { + /*! LengthOfTimeUnit ::= INTEGER (0..16777215) -- 24 bit number */ + u_int32_t length; + /*! + * \details + * oneHundredthSecond(0), + * oneTenthSecond(1), + * oneSecond(2), + * tenSeconds(3), + * oneMinute(4), + * oneHour(5), + * twentyFourHours(6) + */ + u_int8_t scale; +}; + +/* + * Amount ::= SEQUENCE { + * currencyAmount [1] IMPLICIT CurrencyAmount, + * multiplier [2] IMPLICIT Multiplier + * } + */ +struct roseQsigAOCAmount { + /*! CurrencyAmount ::= INTEGER (0..16777215) -- 24 bit number */ + u_int32_t currency; + /*! + * \details + * oneThousandth(0), + * oneHundredth(1), + * oneTenth(2), + * one(3), + * ten(4), + * hundred(5), + * thousand(6) + */ + u_int8_t multiplier; +}; + +/* + * DurationCurrency ::= SEQUENCE { + * dCurrency [1] IMPLICIT Currency, + * dAmount [2] IMPLICIT Amount, + * dChargingType [3] IMPLICIT ChargingType, + * dTime [4] IMPLICIT Time, + * dGranularity [5] IMPLICIT Time OPTIONAL + * } + */ +struct roseQsigAOCDurationCurrency { + struct roseQsigAOCAmount amount; + struct roseQsigAOCTime time; + /*! \brief dGranularity (optional) */ + struct roseQsigAOCTime granularity; + /*! + * \brief Name of currency + * \details + * Currency ::= IA5String (SIZE (0..10)) + * \note The empty string is the default currency for the network. + */ + unsigned char currency[10 + 1]; + /*! + * \details + * continuousCharging(0), + * stepFunction(1) + */ + u_int8_t charging_type; + /*! TRUE if granularity time is present */ + u_int8_t granularity_present; +}; + +/* + * FlatRateCurrency ::= SEQUENCE { + * fRCurrency [1] IMPLICIT Currency, + * fRAmount [2] IMPLICIT Amount + * } + */ +struct roseQsigAOCFlatRateCurrency { + struct roseQsigAOCAmount amount; + /*! + * \brief Name of currency + * \details + * Currency ::= IA5String (SIZE (0..10)) + * \note The empty string is the default currency for the network. + */ + unsigned char currency[10 + 1]; +}; + +/* + * VolumeRateCurrency ::= SEQUENCE { + * vRCurrency [1] IMPLICIT Currency, + * vRAmount [2] IMPLICIT Amount, + * vRVolumeUnit [3] IMPLICIT VolumeUnit + * } + */ +struct roseQsigAOCVolumeRateCurrency { + struct roseQsigAOCAmount amount; + /*! + * \brief Name of currency + * \details + * Currency ::= IA5String (SIZE (0..10)) + * \note The empty string is the default currency for the network. + */ + unsigned char currency[10 + 1]; + /*! + * \brief Volume rate volume unit + * \details + * octet(0), + * segment(1), + * message(2) + */ + u_int8_t unit; +}; + +/* + * AOCSCurrencyInfo ::= SEQUENCE { + * chargedItem ChargedItem, + * rateType CHOICE { + * durationCurrency [1] IMPLICIT DurationCurrency, + * flatRateCurrency [2] IMPLICIT FlatRateCurrency, + * volumeRateCurrency [3] IMPLICIT VolumeRateCurrency, + * specialChargingCode SpecialChargingCode, + * freeOfCharge [4] IMPLICIT NULL, + * currencyInfoNotAvailable [5] IMPLICIT NULL, + * freeOfChargefromBeginning [6] IMPLICIT NULL + * } + * } + */ +struct roseQsigAOCSCurrencyInfo { + union { + struct roseQsigAOCDurationCurrency duration; + struct roseQsigAOCFlatRateCurrency flat_rate; + struct roseQsigAOCVolumeRateCurrency volume_rate; + /*! SpecialChargingCode ::= INTEGER (1..10) */ + u_int8_t special_charging_code; + } u; + /*! + * \brief Determine what is stored in the union. + * \details + * specialChargingCode(0), + * durationCurrency(1), + * flatRateCurrency(2), + * volumeRateCurrency(3), + * freeOfCharge(4), + * currencyInfoNotAvailable(5), + * freeOfChargeFromBeginning(6) + */ + u_int8_t currency_type; + /*! + * \brief What service is being billed. + * \details + * basicCommunication(0), + * callAttempt(1), + * callSetup(2), + * userToUserInfo(3), + * operationOfSupplementaryServ(4) + */ + u_int8_t charged_item; +}; + +/* + * AOCSCurrencyInfoList ::= SEQUENCE SIZE (1..10) OF AOCSCurrencyInfo + */ +struct roseQsigAOCSCurrencyInfoList { + /*! \brief SEQUENCE SIZE (1..10) OF AOCSCurrencyInfo */ + struct roseQsigAOCSCurrencyInfo list[10]; + + /*! \brief Number of AOCSCurrencyInfo records present */ + u_int8_t num_records; +}; + +/* + * RecordedCurrency ::= SEQUENCE { + * rCurrency [1] IMPLICIT Currency, + * rAmount [2] IMPLICIT Amount + * } + */ +struct roseQsigAOCRecordedCurrency { + /*! Amount of currency involved. */ + struct roseQsigAOCAmount amount; + /*! + * \brief Name of currency + * \details + * Currency ::= IA5String (SIZE (0..10)) + * \note The empty string is the default currency for the network. + */ + unsigned char currency[10 + 1]; +}; + +/* + * ChargingAssociation ::= CHOICE { + * chargedNumber [0] EXPLICIT PartyNumber, + * chargeIdentifier ChargeIdentifier + * } + */ +struct roseQsigAOCChargingAssociation { + /*! chargeIdentifier: INTEGER (-32768..32767) -- 16 bit number */ + int16_t id; + /*! chargedNumber */ + struct rosePartyNumber number; + /*! + * \details + * charge_identifier(0) + * charged_number(1), + */ + u_int8_t type; +}; + +/* + * AocRateArg ::= SEQUENCE { + * aocRate CHOICE + * { + * chargeNotAvailable NULL, + * aocSCurrencyInfoList AOCSCurrencyInfoList + * }, + * rateArgExtension CHOICE { + * extension [1] IMPLICIT Extension, + * multipleExtension [2] IMPLICIT SEQUENCE OF Extension + * } OPTIONAL + * } + */ +struct roseQsigAocRateArg_ARG { + struct roseQsigAOCSCurrencyInfoList currency_info; + /*! + * \details + * charge_not_available(0), + * currency_info_list(1) + */ + u_int8_t type; +}; + +/* + * AocInterimArg ::= SEQUENCE { + * interimCharge CHOICE { + * chargeNotAvailable [0] IMPLICIT NULL, + * freeOfCharge [1] IMPLICIT NULL, + * specificCurrency SEQUENCE { + * recordedCurrency [1] IMPLICIT RecordedCurrency, + * interimBillingId [2] IMPLICIT InterimBillingId OPTIONAL + * } + * }, + * interimArgExtension CHOICE { + * extension [1] IMPLICIT Extension, + * multipleExtension [2] IMPLICIT SEQUENCE OF Extension + * } OPTIONAL + * } + */ +struct roseQsigAocInterimArg_ARG { + struct { + /*! \brief recorded currency */ + struct roseQsigAOCRecordedCurrency recorded; + /*! + * \brief InterimBillingId (optional) + * \details + * normalCharging(0), + * creditCardCharging(2) + */ + u_int8_t billing_id; + /*! \brief TRUE if billing id is present */ + u_int8_t billing_id_present; + } specific; + /*! + * \details + * charge_not_available(0), + * free_of_charge(1), + * specific_currency(2) + */ + u_int8_t type; +}; + +/* + * AocFinalArg ::= SEQUENCE { + * finalCharge CHOICE { + * chargeNotAvailable [0] IMPLICIT NULL, + * freeOfCharge [1] IMPLICIT NULL, + * specificCurrency SEQUENCE { + * recordedCurrency [1] IMPLICIT RecordedCurrency, + * finalBillingId [2] IMPLICIT FinalBillingId OPTIONAL + * } + * }, + * chargingAssociation ChargingAssociation OPTIONAL, + * finalArgExtension CHOICE { + * extension [1] IMPLICIT Extension, + * multipleExtension [2] IMPLICIT SEQUENCE OF Extension + * } OPTIONAL + * } + */ +struct roseQsigAocFinalArg_ARG { + struct { + /*! \brief recorded currency */ + struct roseQsigAOCRecordedCurrency recorded; + /*! + * \brief FinalBillingId (optional) + * \details + * normalCharging(0), + * creditCardCharging(2), + * callForwardingUnconditional(3), + * callForwardingBusy(4), + * callForwardingNoReply(5), + * callDeflection(6), + * callTransfer(7) + */ + u_int8_t billing_id; + /*! \brief TRUE if billing id is present */ + u_int8_t billing_id_present; + } specific; + + /*! \brief chargingAssociation (optional) */ + struct roseQsigAOCChargingAssociation charging_association; + + /*! \brief TRUE if charging_association is present */ + u_int8_t charging_association_present; + + /*! + * \details + * charge_not_available(0), + * free_of_charge(1), + * specific_currency(2) + */ + u_int8_t type; +}; + +/* + * ChargeRequestArg ::= SEQUENCE { + * adviceModeCombinations SEQUENCE SIZE(0..7) OF AdviceModeCombination, + * chargeReqArgExtension CHOICE { + * extension [1] IMPLICIT Extension, + * multipleExtension [2] IMPLICIT SEQUENCE OF Extension + * } OPTIONAL + * } + */ +struct roseQsigChargeRequestArg_ARG { + /*! + * \brief SEQUENCE SIZE(0..7) OF AdviceModeCombination + * \details + * rate(0) , + * rateInterim(1) , + * rateFinal(2) , + * interim(3) , + * final(4) , + * interimFinal(5) , + * rateInterimFinal(6) + */ + u_int8_t advice_mode_combinations[7]; + + /*! \brief Number of AdviceModeCombination values present */ + u_int8_t num_records; +}; + +/* + * ChargeRequestRes ::= SEQUENCE { + * adviceModeCombination AdviceModeCombination, + * chargeReqResExtension CHOICE { + * extension [1] IMPLICIT Extension, + * multipleExtension [2] IMPLICIT SEQUENCE OF Extension + * } OPTIONAL + * } + */ +struct roseQsigChargeRequestRes_RES { + /*! + * \details + * rate(0) , + * rateInterim(1) , + * rateFinal(2) , + * interim(3) , + * final(4) , + * interimFinal(5) , + * rateInterimFinal(6) + */ + u_int8_t advice_mode_combination; +}; + +/* + * AocCompleteArg ::= SEQUENCE { + * chargedUser PartyNumber, + * chargingAssociation ChargingAssociation OPTIONAL, + * completeArgExtension CHOICE { + * extension [1] IMPLICIT Extension, + * multipleExtension [2] IMPLICIT SEQUENCE OF Extension + * } OPTIONAL + * } + */ +struct roseQsigAocCompleteArg_ARG { + /*! \brief chargingAssociation (optional) */ + struct roseQsigAOCChargingAssociation charging_association; + + struct rosePartyNumber charged_user_number; + + /*! \brief TRUE if charging_association is present */ + u_int8_t charging_association_present; +}; + +/* + * AocCompleteRes ::= SEQUENCE { + * chargingOption ChargingOption, + * completeResExtension CHOICE { + * extension [1] IMPLICIT Extension, + * multipleExtension [2] IMPLICIT SEQUENCE OF Extension + * } OPTIONAL + * } + */ +struct roseQsigAocCompleteRes_RES { + /*! + * \details + * aocFreeOfCharge(0), + * aocContinueCharging(1), + * aocStopCharging(2) + */ + u_int8_t charging_option; +}; + +/* + * AocDivChargeReqArg ::= SEQUENCE { + * divertingUser PartyNumber, + * chargingAssociation ChargingAssociation OPTIONAL, + * diversionType DiversionType, + * aocDivChargeReqArgExt CHOICE { + * extension [1] IMPLICIT Extension, + * multipleExtension [2] IMPLICIT SEQUENCE OF Extension + * } OPTIONAL + * } + */ +struct roseQsigAocDivChargeReqArg_ARG { + /*! \brief chargingAssociation (optional) */ + struct roseQsigAOCChargingAssociation charging_association; + + struct rosePartyNumber diverting_user_number; + + /*! \brief TRUE if charging_association is present */ + u_int8_t charging_association_present; + + /*! + * \details + * callForwardingUnconditional(0), + * callForwardingBusy(1), + * callForwardingNoReply(2), + * callDeflection(3) + */ + u_int8_t diversion_type; +}; + + +/* ------------------------------------------------------------------- */ + + /* * CTIdentifyRes ::= SEQUENCE { * callIdentity CallIdentity, @@ -2193,6 +2654,14 @@ union rose_msg_invoke_qsig_args { struct roseQsigPartyName_ARG ConnectedName; struct roseQsigPartyName_ARG BusyName; + /* Q.SIG SS-AOC-Operations */ + struct roseQsigChargeRequestArg_ARG ChargeRequest; + struct roseQsigAocFinalArg_ARG AocFinal; + struct roseQsigAocInterimArg_ARG AocInterim; + struct roseQsigAocRateArg_ARG AocRate; + struct roseQsigAocCompleteArg_ARG AocComplete; + struct roseQsigAocDivChargeReqArg_ARG AocDivChargeReq; + /* Q.SIG Call-Transfer-Operations */ struct roseQsigCTInitiateArg_ARG CallTransferInitiate; struct roseQsigCTSetupArg_ARG CallTransferSetup; @@ -2219,6 +2688,10 @@ union rose_msg_invoke_qsig_args { /*! \brief Facility ie result qsig messages with arguments. */ union rose_msg_result_qsig_args { + /* Q.SIG SS-AOC-Operations */ + struct roseQsigChargeRequestRes_RES ChargeRequest; + struct roseQsigAocCompleteRes_RES AocComplete; + /* Q.SIG Call-Transfer-Operations */ struct roseQsigCTIdentifyRes_RES CallTransferIdentify; diff --git a/rose_internal.h b/rose_internal.h index 9267bce..52af967 100644 --- a/rose_internal.h +++ b/rose_internal.h @@ -169,9 +169,10 @@ const unsigned char *rose_dec_qsig_BusyName_ARG(struct pri *ctrl, unsigned tag, /* * Q.SIG Dummy invoke/result argument used by: + * SS-AOC-Operations, * Call-Transfer-Operations, - * Call-Diversion-Operations, - * and SS-MWI-Operations + * Call-Diversion-Operations, + * and SS-MWI-Operations. */ unsigned char *rose_enc_qsig_DummyArg_ARG(struct pri *ctrl, unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args); @@ -185,6 +186,49 @@ const unsigned char *rose_dec_qsig_DummyRes_RES(struct pri *ctrl, unsigned tag, const unsigned char *pos, const unsigned char *end, union rose_msg_result_args *args); +/* Q.SIG SS-AOC-Operations */ +unsigned char *rose_enc_qsig_ChargeRequest_ARG(struct pri *ctrl, unsigned char *pos, + unsigned char *end, const union rose_msg_invoke_args *args); +unsigned char *rose_enc_qsig_ChargeRequest_RES(struct pri *ctrl, unsigned char *pos, + unsigned char *end, const union rose_msg_result_args *args); +unsigned char *rose_enc_qsig_AocFinal_ARG(struct pri *ctrl, unsigned char *pos, + unsigned char *end, const union rose_msg_invoke_args *args); +unsigned char *rose_enc_qsig_AocInterim_ARG(struct pri *ctrl, unsigned char *pos, + unsigned char *end, const union rose_msg_invoke_args *args); +unsigned char *rose_enc_qsig_AocRate_ARG(struct pri *ctrl, unsigned char *pos, + unsigned char *end, const union rose_msg_invoke_args *args); +unsigned char *rose_enc_qsig_AocComplete_ARG(struct pri *ctrl, unsigned char *pos, + unsigned char *end, const union rose_msg_invoke_args *args); +unsigned char *rose_enc_qsig_AocComplete_RES(struct pri *ctrl, unsigned char *pos, + unsigned char *end, const union rose_msg_result_args *args); +unsigned char *rose_enc_qsig_AocDivChargeReq_ARG(struct pri *ctrl, unsigned char *pos, + unsigned char *end, const union rose_msg_invoke_args *args); + +const unsigned char *rose_dec_qsig_ChargeRequest_ARG(struct pri *ctrl, unsigned tag, + const unsigned char *pos, const unsigned char *end, + union rose_msg_invoke_args *args); +const unsigned char *rose_dec_qsig_ChargeRequest_RES(struct pri *ctrl, unsigned tag, + const unsigned char *pos, const unsigned char *end, + union rose_msg_result_args *args); +const unsigned char *rose_dec_qsig_AocFinal_ARG(struct pri *ctrl, unsigned tag, + const unsigned char *pos, const unsigned char *end, + union rose_msg_invoke_args *args); +const unsigned char *rose_dec_qsig_AocInterim_ARG(struct pri *ctrl, unsigned tag, + const unsigned char *pos, const unsigned char *end, + union rose_msg_invoke_args *args); +const unsigned char *rose_dec_qsig_AocRate_ARG(struct pri *ctrl, unsigned tag, + const unsigned char *pos, const unsigned char *end, + union rose_msg_invoke_args *args); +const unsigned char *rose_dec_qsig_AocComplete_ARG(struct pri *ctrl, unsigned tag, + const unsigned char *pos, const unsigned char *end, + union rose_msg_invoke_args *args); +const unsigned char *rose_dec_qsig_AocComplete_RES(struct pri *ctrl, unsigned tag, + const unsigned char *pos, const unsigned char *end, + union rose_msg_result_args *args); +const unsigned char *rose_dec_qsig_AocDivChargeReq_ARG(struct pri *ctrl, unsigned tag, + const unsigned char *pos, const unsigned char *end, + union rose_msg_invoke_args *args); + /* Q.SIG Call-Diversion-Operations */ unsigned char *rose_enc_qsig_ActivateDiversionQ_ARG(struct pri *ctrl, unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args); diff --git a/rose_qsig_aoc.c b/rose_qsig_aoc.c new file mode 100644 index 0000000..636f69f --- /dev/null +++ b/rose_qsig_aoc.c @@ -0,0 +1,1714 @@ +/* + * libpri: An implementation of Primary Rate ISDN + * + * Copyright (C) 2009 Digium, Inc. + * + * Richard Mudgett + * + * 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 Q.SIG ROSE Advice-Of-Charge (AOC) operations + * + * SS-AOC-Operations ECMA-212 Annex E Table E.1 + * + * \author Richard Mudgett + */ + + +#include "compat.h" +#include "libpri.h" +#include "pri_internal.h" +#include "rose.h" +#include "rose_internal.h" +#include "asn1.h" + + +/* ------------------------------------------------------------------- */ + +/*! + * \internal + * \brief Encode the Time 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 time Time information to encode. + * + * \retval Start of the next ASN.1 component to encode on success. + * \retval NULL on error. + */ +static unsigned char *rose_enc_qsig_AOC_Time(struct pri *ctrl, unsigned char *pos, + unsigned char *end, unsigned tag, const struct roseQsigAOCTime *time) +{ + unsigned char *seq_len; + + ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag); + + ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1, + time->length)); + ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2, time->scale)); + + ASN1_CONSTRUCTED_END(seq_len, pos, end); + + return pos; +} + +/*! + * \internal + * \brief Encode the Amount 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 amount Amount information to encode. + * + * \retval Start of the next ASN.1 component to encode on success. + * \retval NULL on error. + */ +static unsigned char *rose_enc_qsig_AOC_Amount(struct pri *ctrl, unsigned char *pos, + unsigned char *end, unsigned tag, const struct roseQsigAOCAmount *amount) +{ + unsigned char *seq_len; + + ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag); + + ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1, + amount->currency)); + ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2, + amount->multiplier)); + + ASN1_CONSTRUCTED_END(seq_len, pos, end); + + return pos; +} + +/*! + * \internal + * \brief Encode the RecordedCurrency 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 recorded Recorded currency information to encode. + * + * \retval Start of the next ASN.1 component to encode on success. + * \retval NULL on error. + */ +static unsigned char *rose_enc_qsig_AOC_RecordedCurrency(struct pri *ctrl, + unsigned char *pos, unsigned char *end, unsigned tag, + const struct roseQsigAOCRecordedCurrency *recorded) +{ + unsigned char *seq_len; + + ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag); + + ASN1_CALL(pos, asn1_enc_string_max(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1, + recorded->currency, sizeof(recorded->currency) - 1)); + ASN1_CALL(pos, rose_enc_qsig_AOC_Amount(ctrl, pos, end, + ASN1_CLASS_CONTEXT_SPECIFIC | 2, &recorded->amount)); + + ASN1_CONSTRUCTED_END(seq_len, pos, end); + + return pos; +} + +/*! + * \internal + * \brief Encode the DurationCurrency 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 duration Duration currency information to encode. + * + * \retval Start of the next ASN.1 component to encode on success. + * \retval NULL on error. + */ +static unsigned char *rose_enc_qsig_AOC_DurationCurrency(struct pri *ctrl, + unsigned char *pos, unsigned char *end, unsigned tag, + const struct roseQsigAOCDurationCurrency *duration) +{ + unsigned char *seq_len; + + ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag); + + ASN1_CALL(pos, asn1_enc_string_max(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1, + duration->currency, sizeof(duration->currency) - 1)); + ASN1_CALL(pos, rose_enc_qsig_AOC_Amount(ctrl, pos, end, + ASN1_CLASS_CONTEXT_SPECIFIC | 2, &duration->amount)); + ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 3, + duration->charging_type)); + ASN1_CALL(pos, rose_enc_qsig_AOC_Time(ctrl, pos, end, + ASN1_CLASS_CONTEXT_SPECIFIC | 4, &duration->time)); + if (duration->granularity_present) { + ASN1_CALL(pos, rose_enc_qsig_AOC_Time(ctrl, pos, end, + ASN1_CLASS_CONTEXT_SPECIFIC | 5, &duration->granularity)); + } + + ASN1_CONSTRUCTED_END(seq_len, pos, end); + + return pos; +} + +/*! + * \internal + * \brief Encode the FlatRateCurrency 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 flat_rate Flat rate currency information to encode. + * + * \retval Start of the next ASN.1 component to encode on success. + * \retval NULL on error. + */ +static unsigned char *rose_enc_qsig_AOC_FlatRateCurrency(struct pri *ctrl, + unsigned char *pos, unsigned char *end, unsigned tag, + const struct roseQsigAOCFlatRateCurrency *flat_rate) +{ + unsigned char *seq_len; + + ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag); + + ASN1_CALL(pos, asn1_enc_string_max(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1, + flat_rate->currency, sizeof(flat_rate->currency) - 1)); + ASN1_CALL(pos, rose_enc_qsig_AOC_Amount(ctrl, pos, end, + ASN1_CLASS_CONTEXT_SPECIFIC | 2, &flat_rate->amount)); + + ASN1_CONSTRUCTED_END(seq_len, pos, end); + + return pos; +} + +/*! + * \internal + * \brief Encode the VolumeRateCurrency 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 volume_rate Volume rate currency information to encode. + * + * \retval Start of the next ASN.1 component to encode on success. + * \retval NULL on error. + */ +static unsigned char *rose_enc_qsig_AOC_VolumeRateCurrency(struct pri *ctrl, + unsigned char *pos, unsigned char *end, unsigned tag, + const struct roseQsigAOCVolumeRateCurrency *volume_rate) +{ + unsigned char *seq_len; + + ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag); + + ASN1_CALL(pos, asn1_enc_string_max(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1, + volume_rate->currency, sizeof(volume_rate->currency) - 1)); + ASN1_CALL(pos, rose_enc_qsig_AOC_Amount(ctrl, pos, end, + ASN1_CLASS_CONTEXT_SPECIFIC | 2, &volume_rate->amount)); + ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 3, + volume_rate->unit)); + + ASN1_CONSTRUCTED_END(seq_len, pos, end); + + return pos; +} + +/*! + * \internal + * \brief Encode the AOCSCurrencyInfo 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 currency_info Currency information record to encode. + * + * \retval Start of the next ASN.1 component to encode on success. + * \retval NULL on error. + */ +static unsigned char *rose_enc_qsig_AOCSCurrencyInfo(struct pri *ctrl, + unsigned char *pos, unsigned char *end, unsigned tag, + const struct roseQsigAOCSCurrencyInfo *currency_info) +{ + unsigned char *seq_len; + + ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag); + + ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, + currency_info->charged_item)); + + switch (currency_info->currency_type) { + case 0: /* specialChargingCode */ + ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_INTEGER, + currency_info->u.special_charging_code)); + break; + case 1: /* durationCurrency */ + ASN1_CALL(pos, rose_enc_qsig_AOC_DurationCurrency(ctrl, pos, end, + ASN1_CLASS_CONTEXT_SPECIFIC | 1, ¤cy_info->u.duration)); + break; + case 2: /* flatRateCurrency */ + ASN1_CALL(pos, rose_enc_qsig_AOC_FlatRateCurrency(ctrl, pos, end, + ASN1_CLASS_CONTEXT_SPECIFIC | 2, ¤cy_info->u.flat_rate)); + break; + case 3: /* volumeRateCurrency */ + ASN1_CALL(pos, rose_enc_qsig_AOC_VolumeRateCurrency(ctrl, pos, end, + ASN1_CLASS_CONTEXT_SPECIFIC | 3, ¤cy_info->u.volume_rate)); + break; + case 4: /* freeOfCharge */ + ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 4)); + break; + case 5: /* currencyInfoNotAvailable */ + ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 5)); + break; + case 6: /* freeOfChargeFromBeginning */ + ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 6)); + break; + default: + ASN1_ENC_ERROR(ctrl, "Unknown currency type"); + return NULL; + } + + ASN1_CONSTRUCTED_END(seq_len, pos, end); + + return pos; +} + +/*! + * \internal + * \brief Encode the AOCSCurrencyInfoList 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 currency_info Currency information list to encode. + * + * \retval Start of the next ASN.1 component to encode on success. + * \retval NULL on error. + */ +static unsigned char *rose_enc_qsig_AOCSCurrencyInfoList(struct pri *ctrl, + unsigned char *pos, unsigned char *end, unsigned tag, + const struct roseQsigAOCSCurrencyInfoList *currency_info) +{ + unsigned index; + unsigned char *seq_len; + + ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag); + + for (index = 0; index < currency_info->num_records; ++index) { + ASN1_CALL(pos, rose_enc_qsig_AOCSCurrencyInfo(ctrl, pos, end, ASN1_TAG_SEQUENCE, + ¤cy_info->list[index])); + } + + ASN1_CONSTRUCTED_END(seq_len, pos, end); + + return pos; +} + +/*! + * \internal + * \brief Encode the ChargingAssociation 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 charging Charging association information to encode. + * + * \retval Start of the next ASN.1 component to encode on success. + * \retval NULL on error. + */ +static unsigned char *rose_enc_qsig_AOC_ChargingAssociation(struct pri *ctrl, + unsigned char *pos, unsigned char *end, + const struct roseQsigAOCChargingAssociation *charging) +{ + unsigned char *explicit_len; + + switch (charging->type) { + case 0: /* charge_identifier */ + ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_INTEGER, charging->id)); + break; + case 1: /* charged_number */ + /* EXPLICIT tag */ + ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 0); + ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, &charging->number)); + ASN1_CONSTRUCTED_END(explicit_len, pos, end); + break; + default: + ASN1_ENC_ERROR(ctrl, "Unknown ChargingAssociation type"); + return NULL; + } + + return pos; +} + +/*! + * \brief Encode the Q.SIG ChargeRequest invoke facility ie arguments. + * + * \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 args Arguments to encode in the buffer. + * + * \retval Start of the next ASN.1 component to encode on success. + * \retval NULL on error. + */ +unsigned char *rose_enc_qsig_ChargeRequest_ARG(struct pri *ctrl, unsigned char *pos, + unsigned char *end, const union rose_msg_invoke_args *args) +{ + unsigned index; + unsigned char *seq_len; + unsigned char *advice_len; + const struct roseQsigChargeRequestArg_ARG *charge_request; + + charge_request = &args->qsig.ChargeRequest; + + ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE); + + /* SEQUENCE SIZE(0..7) OF AdviceModeCombination */ + ASN1_CONSTRUCTED_BEGIN(advice_len, pos, end, ASN1_TAG_SEQUENCE); + for (index = 0; index < charge_request->num_records; ++index) { + ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, + charge_request->advice_mode_combinations[index])); + } + ASN1_CONSTRUCTED_END(advice_len, pos, end); + + /* No extension to encode */ + + ASN1_CONSTRUCTED_END(seq_len, pos, end); + + return pos; +} + +/*! + * \brief Encode the Q.SIG ChargeRequest result facility ie arguments. + * + * \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 args Arguments to encode in the buffer. + * + * \retval Start of the next ASN.1 component to encode on success. + * \retval NULL on error. + */ +unsigned char *rose_enc_qsig_ChargeRequest_RES(struct pri *ctrl, unsigned char *pos, + unsigned char *end, const union rose_msg_result_args *args) +{ + unsigned char *seq_len; + const struct roseQsigChargeRequestRes_RES *charge_request; + + charge_request = &args->qsig.ChargeRequest; + + ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE); + + ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, + charge_request->advice_mode_combination)); + + /* No extension to encode */ + + ASN1_CONSTRUCTED_END(seq_len, pos, end); + + return pos; +} + +/*! + * \brief Encode the Q.SIG AocFinal invoke facility ie arguments. + * + * \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 args Arguments to encode in the buffer. + * + * \retval Start of the next ASN.1 component to encode on success. + * \retval NULL on error. + */ +unsigned char *rose_enc_qsig_AocFinal_ARG(struct pri *ctrl, unsigned char *pos, + unsigned char *end, const union rose_msg_invoke_args *args) +{ + unsigned char *seq_len; + unsigned char *specific_len; + const struct roseQsigAocFinalArg_ARG *aoc_final; + + aoc_final = &args->qsig.AocFinal; + + ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE); + + switch (aoc_final->type) { + case 0: /* charge_not_available */ + ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 0)); + break; + case 1: /* free_of_charge */ + ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1)); + break; + case 2: /* specific_currency */ + ASN1_CONSTRUCTED_BEGIN(specific_len, pos, end, ASN1_TAG_SEQUENCE); + + ASN1_CALL(pos, rose_enc_qsig_AOC_RecordedCurrency(ctrl, pos, end, + ASN1_CLASS_CONTEXT_SPECIFIC | 1, &aoc_final->specific.recorded)); + + if (aoc_final->specific.billing_id_present) { + ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2, + aoc_final->specific.billing_id)); + } + + ASN1_CONSTRUCTED_END(specific_len, pos, end); + break; + default: + ASN1_ENC_ERROR(ctrl, "Unknown AocFinal type"); + return NULL; + } + + if (aoc_final->charging_association_present) { + ASN1_CALL(pos, rose_enc_qsig_AOC_ChargingAssociation(ctrl, pos, end, + &aoc_final->charging_association)); + } + + /* No extension to encode */ + + ASN1_CONSTRUCTED_END(seq_len, pos, end); + + return pos; +} + +/*! + * \brief Encode the Q.SIG AocInterim invoke facility ie arguments. + * + * \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 args Arguments to encode in the buffer. + * + * \retval Start of the next ASN.1 component to encode on success. + * \retval NULL on error. + */ +unsigned char *rose_enc_qsig_AocInterim_ARG(struct pri *ctrl, unsigned char *pos, + unsigned char *end, const union rose_msg_invoke_args *args) +{ + unsigned char *seq_len; + unsigned char *specific_len; + const struct roseQsigAocInterimArg_ARG *aoc_interim; + + aoc_interim = &args->qsig.AocInterim; + + ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE); + + switch (aoc_interim->type) { + case 0: /* charge_not_available */ + ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 0)); + break; + case 1: /* free_of_charge */ + ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1)); + break; + case 2: /* specific_currency */ + ASN1_CONSTRUCTED_BEGIN(specific_len, pos, end, ASN1_TAG_SEQUENCE); + + ASN1_CALL(pos, rose_enc_qsig_AOC_RecordedCurrency(ctrl, pos, end, + ASN1_CLASS_CONTEXT_SPECIFIC | 1, &aoc_interim->specific.recorded)); + + if (aoc_interim->specific.billing_id_present) { + ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2, + aoc_interim->specific.billing_id)); + } + + ASN1_CONSTRUCTED_END(specific_len, pos, end); + break; + default: + ASN1_ENC_ERROR(ctrl, "Unknown AocInterim type"); + return NULL; + } + + /* No extension to encode */ + + ASN1_CONSTRUCTED_END(seq_len, pos, end); + + return pos; +} + +/*! + * \brief Encode the Q.SIG AocRate invoke facility ie arguments. + * + * \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 args Arguments to encode in the buffer. + * + * \retval Start of the next ASN.1 component to encode on success. + * \retval NULL on error. + */ +unsigned char *rose_enc_qsig_AocRate_ARG(struct pri *ctrl, unsigned char *pos, + unsigned char *end, const union rose_msg_invoke_args *args) +{ + unsigned char *seq_len; + const struct roseQsigAocRateArg_ARG *aoc_rate; + + aoc_rate = &args->qsig.AocRate; + + ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE); + + switch (aoc_rate->type) { + case 0: /* charge_not_available */ + ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_TYPE_NULL)); + break; + case 1: /* currency_info_list */ + ASN1_CALL(pos, rose_enc_qsig_AOCSCurrencyInfoList(ctrl, pos, end, + ASN1_TAG_SEQUENCE, &aoc_rate->currency_info)); + break; + default: + ASN1_ENC_ERROR(ctrl, "Unknown AocRate type"); + return NULL; + } + + /* No extension to encode */ + + ASN1_CONSTRUCTED_END(seq_len, pos, end); + + return pos; +} + +/*! + * \brief Encode the Q.SIG AocComplete invoke facility ie arguments. + * + * \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 args Arguments to encode in the buffer. + * + * \retval Start of the next ASN.1 component to encode on success. + * \retval NULL on error. + */ +unsigned char *rose_enc_qsig_AocComplete_ARG(struct pri *ctrl, unsigned char *pos, + unsigned char *end, const union rose_msg_invoke_args *args) +{ + unsigned char *seq_len; + const struct roseQsigAocCompleteArg_ARG *aoc_complete; + + aoc_complete = &args->qsig.AocComplete; + + ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE); + + ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, + &aoc_complete->charged_user_number)); + + if (aoc_complete->charging_association_present) { + ASN1_CALL(pos, rose_enc_qsig_AOC_ChargingAssociation(ctrl, pos, end, + &aoc_complete->charging_association)); + } + + /* No extension to encode */ + + ASN1_CONSTRUCTED_END(seq_len, pos, end); + + return pos; +} + +/*! + * \brief Encode the Q.SIG AocComplete result facility ie arguments. + * + * \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 args Arguments to encode in the buffer. + * + * \retval Start of the next ASN.1 component to encode on success. + * \retval NULL on error. + */ +unsigned char *rose_enc_qsig_AocComplete_RES(struct pri *ctrl, unsigned char *pos, + unsigned char *end, const union rose_msg_result_args *args) +{ + unsigned char *seq_len; + const struct roseQsigAocCompleteRes_RES *aoc_complete; + + aoc_complete = &args->qsig.AocComplete; + + ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE); + + ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, + aoc_complete->charging_option)); + + /* No extension to encode */ + + ASN1_CONSTRUCTED_END(seq_len, pos, end); + + return pos; +} + +/*! + * \brief Encode the Q.SIG AocDivChargeReq invoke facility ie arguments. + * + * \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 args Arguments to encode in the buffer. + * + * \retval Start of the next ASN.1 component to encode on success. + * \retval NULL on error. + */ +unsigned char *rose_enc_qsig_AocDivChargeReq_ARG(struct pri *ctrl, unsigned char *pos, + unsigned char *end, const union rose_msg_invoke_args *args) +{ + unsigned char *seq_len; + const struct roseQsigAocDivChargeReqArg_ARG *aoc_div_charge_req; + + aoc_div_charge_req = &args->qsig.AocDivChargeReq; + + ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE); + + ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, + &aoc_div_charge_req->diverting_user_number)); + + if (aoc_div_charge_req->charging_association_present) { + ASN1_CALL(pos, rose_enc_qsig_AOC_ChargingAssociation(ctrl, pos, end, + &aoc_div_charge_req->charging_association)); + } + + ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, + aoc_div_charge_req->diversion_type)); + + /* No extension to encode */ + + ASN1_CONSTRUCTED_END(seq_len, pos, end); + + return pos; +} + +/*! + * \internal + * \brief Decode the Time type. + * + * \param ctrl D channel controller for diagnostic messages or global options. + * \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 time Parameter storage to fill. + * + * \retval Start of the next ASN.1 component on success. + * \retval NULL on error. + */ +static const unsigned char *rose_dec_qsig_AOC_Time(struct pri *ctrl, const char *name, + unsigned tag, const unsigned char *pos, const unsigned char *end, + struct roseQsigAOCTime *time) +{ + int32_t value; + int length; + int seq_offset; + const unsigned char *seq_end; + + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " %s Time %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_CLASS_CONTEXT_SPECIFIC | 1); + ASN1_CALL(pos, asn1_dec_int(ctrl, "lengthOfTimeUnit", tag, pos, seq_end, &value)); + time->length = value; + + ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); + ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 2); + ASN1_CALL(pos, asn1_dec_int(ctrl, "scale", tag, pos, seq_end, &value)); + time->scale = value; + + ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); + + return pos; +} + +/*! + * \internal + * \brief Decode the Amount type. + * + * \param ctrl D channel controller for diagnostic messages or global options. + * \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 amount Parameter storage to fill. + * + * \retval Start of the next ASN.1 component on success. + * \retval NULL on error. + */ +static const unsigned char *rose_dec_qsig_AOC_Amount(struct pri *ctrl, const char *name, + unsigned tag, const unsigned char *pos, const unsigned char *end, + struct roseQsigAOCAmount *amount) +{ + int32_t value; + int length; + int seq_offset; + const unsigned char *seq_end; + + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " %s Amount %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_CLASS_CONTEXT_SPECIFIC | 1); + ASN1_CALL(pos, asn1_dec_int(ctrl, "currencyAmount", tag, pos, seq_end, &value)); + amount->currency = value; + + ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); + ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 2); + ASN1_CALL(pos, asn1_dec_int(ctrl, "multiplier", tag, pos, seq_end, &value)); + amount->multiplier = value; + + ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); + + return pos; +} + +/*! + * \internal + * \brief Decode the RecordedCurrency type. + * + * \param ctrl D channel controller for diagnostic messages or global options. + * \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 recorded Parameter storage to fill. + * + * \retval Start of the next ASN.1 component on success. + * \retval NULL on error. + */ +static const unsigned char *rose_dec_qsig_AOC_RecordedCurrency(struct pri *ctrl, + const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end, + struct roseQsigAOCRecordedCurrency *recorded) +{ + int length; + int seq_offset; + const unsigned char *seq_end; + size_t str_len; + + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " %s RecordedCurrency %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 & ~ASN1_PC_MASK, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 1); + ASN1_CALL(pos, asn1_dec_string_max(ctrl, "rCurrency", tag, pos, seq_end, + sizeof(recorded->currency), recorded->currency, &str_len)); + + ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); + ASN1_CHECK_TAG(ctrl, tag, tag, + ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2); + ASN1_CALL(pos, rose_dec_qsig_AOC_Amount(ctrl, "rAmount", tag, pos, seq_end, + &recorded->amount)); + + ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); + + return pos; +} + +/*! + * \internal + * \brief Decode the DurationCurrency type. + * + * \param ctrl D channel controller for diagnostic messages or global options. + * \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 duration Parameter storage to fill. + * + * \retval Start of the next ASN.1 component on success. + * \retval NULL on error. + */ +static const unsigned char *rose_dec_qsig_AOC_DurationCurrency(struct pri *ctrl, + const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end, + struct roseQsigAOCDurationCurrency *duration) +{ + int32_t value; + int length; + int seq_offset; + const unsigned char *seq_end; + size_t str_len; + + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " %s DurationCurrency %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 & ~ASN1_PC_MASK, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 1); + ASN1_CALL(pos, asn1_dec_string_max(ctrl, "dCurrency", tag, pos, seq_end, + sizeof(duration->currency), duration->currency, &str_len)); + + ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); + ASN1_CHECK_TAG(ctrl, tag, tag, + ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2); + ASN1_CALL(pos, rose_dec_qsig_AOC_Amount(ctrl, "dAmount", tag, pos, seq_end, + &duration->amount)); + + ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); + ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 3); + ASN1_CALL(pos, asn1_dec_int(ctrl, "dChargingType", tag, pos, seq_end, &value)); + duration->charging_type = value; + + ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); + ASN1_CHECK_TAG(ctrl, tag, tag, + ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 4); + ASN1_CALL(pos, rose_dec_qsig_AOC_Time(ctrl, "dTime", tag, pos, seq_end, + &duration->time)); + + if (pos < seq_end && *pos != ASN1_INDEF_TERM) { + ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); + ASN1_CHECK_TAG(ctrl, tag, tag, + ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 5); + ASN1_CALL(pos, rose_dec_qsig_AOC_Time(ctrl, "dGranularity", tag, pos, seq_end, + &duration->granularity)); + duration->granularity_present = 1; + } else { + duration->granularity_present = 0; + } + + ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); + + return pos; +} + +/*! + * \internal + * \brief Decode the FlatRateCurrency type. + * + * \param ctrl D channel controller for diagnostic messages or global options. + * \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 flat_rate Parameter storage to fill. + * + * \retval Start of the next ASN.1 component on success. + * \retval NULL on error. + */ +static const unsigned char *rose_dec_qsig_AOC_FlatRateCurrency(struct pri *ctrl, + const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end, + struct roseQsigAOCFlatRateCurrency *flat_rate) +{ + int length; + int seq_offset; + const unsigned char *seq_end; + size_t str_len; + + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " %s FlatRateCurrency %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 & ~ASN1_PC_MASK, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 1); + ASN1_CALL(pos, asn1_dec_string_max(ctrl, "fRCurrency", tag, pos, seq_end, + sizeof(flat_rate->currency), flat_rate->currency, &str_len)); + + ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); + ASN1_CHECK_TAG(ctrl, tag, tag, + ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2); + ASN1_CALL(pos, rose_dec_qsig_AOC_Amount(ctrl, "fRAmount", tag, pos, seq_end, + &flat_rate->amount)); + + ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); + + return pos; +} + +/*! + * \internal + * \brief Decode the VolumeRateCurrency type. + * + * \param ctrl D channel controller for diagnostic messages or global options. + * \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 volume_rate Parameter storage to fill. + * + * \retval Start of the next ASN.1 component on success. + * \retval NULL on error. + */ +static const unsigned char *rose_dec_qsig_AOC_VolumeRateCurrency(struct pri *ctrl, + const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end, + struct roseQsigAOCVolumeRateCurrency *volume_rate) +{ + int32_t value; + int length; + int seq_offset; + const unsigned char *seq_end; + size_t str_len; + + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " %s VolumeRateCurrency %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 & ~ASN1_PC_MASK, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 1); + ASN1_CALL(pos, asn1_dec_string_max(ctrl, "vRCurrency", tag, pos, seq_end, + sizeof(volume_rate->currency), volume_rate->currency, &str_len)); + + ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); + ASN1_CHECK_TAG(ctrl, tag, tag, + ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2); + ASN1_CALL(pos, rose_dec_qsig_AOC_Amount(ctrl, "vRAmount", tag, pos, seq_end, + &volume_rate->amount)); + + ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); + ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 3); + ASN1_CALL(pos, asn1_dec_int(ctrl, "vRVolumeUnit", tag, pos, seq_end, &value)); + volume_rate->unit = value; + + ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); + + return pos; +} + +/*! + * \internal + * \brief Decode the AOCSCurrencyInfo type. + * + * \param ctrl D channel controller for diagnostic messages or global options. + * \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 currency_info Parameter storage to fill. + * + * \retval Start of the next ASN.1 component on success. + * \retval NULL on error. + */ +static const unsigned char *rose_dec_qsig_AOCSCurrencyInfo(struct pri *ctrl, + const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end, + struct roseQsigAOCSCurrencyInfo *currency_info) +{ + int32_t value; + int length; + int seq_offset; + const unsigned char *seq_end; + + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " %s AOCSCurrencyInfo %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, "chargedItem", tag, pos, seq_end, &value)); + currency_info->charged_item = value; + + ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); + switch (tag) { + case ASN1_TYPE_INTEGER: + currency_info->currency_type = 0; /* specialChargingCode */ + ASN1_CALL(pos, asn1_dec_int(ctrl, "specialChargingCode", tag, pos, seq_end, + &value)); + currency_info->u.special_charging_code = value; + break; + case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1: + currency_info->currency_type = 1; /* durationCurrency */ + ASN1_CALL(pos, rose_dec_qsig_AOC_DurationCurrency(ctrl, "durationCurrency", tag, + pos, seq_end, ¤cy_info->u.duration)); + break; + case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2: + currency_info->currency_type = 2; /* flatRateCurrency */ + ASN1_CALL(pos, rose_dec_qsig_AOC_FlatRateCurrency(ctrl, "flatRateCurrency", tag, + pos, seq_end, ¤cy_info->u.flat_rate)); + break; + case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 3: + currency_info->currency_type = 3; /* volumeRateCurrency */ + ASN1_CALL(pos, rose_dec_qsig_AOC_VolumeRateCurrency(ctrl, "volumeRateCurrency", + tag, pos, seq_end, ¤cy_info->u.volume_rate)); + break; + case ASN1_CLASS_CONTEXT_SPECIFIC | 4: + currency_info->currency_type = 4; /* freeOfCharge */ + ASN1_CALL(pos, asn1_dec_null(ctrl, "freeOfCharge", tag, pos, seq_end)); + break; + case ASN1_CLASS_CONTEXT_SPECIFIC | 5: + currency_info->currency_type = 5; /* currencyInfoNotAvailable */ + ASN1_CALL(pos, asn1_dec_null(ctrl, "currencyInfoNotAvailable", tag, pos, + seq_end)); + break; + case ASN1_CLASS_CONTEXT_SPECIFIC | 6: + currency_info->currency_type = 6; /* freeOfChargeFromBeginning */ + ASN1_CALL(pos, asn1_dec_null(ctrl, "freeOfChargeFromBeginning", tag, pos, + seq_end)); + break; + default: + ASN1_DID_NOT_EXPECT_TAG(ctrl, tag); + return NULL; + } + + ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); + + return pos; +} + +/*! + * \internal + * \brief Decode the AOCSCurrencyInfoList type. + * + * \param ctrl D channel controller for diagnostic messages or global options. + * \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 currency_info Parameter storage to fill. + * + * \retval Start of the next ASN.1 component on success. + * \retval NULL on error. + */ +static const unsigned char *rose_dec_qsig_AOCSCurrencyInfoList(struct pri *ctrl, + const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end, + struct roseQsigAOCSCurrencyInfoList *currency_info) +{ + int length; + int seq_offset; + const unsigned char *seq_end; + + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " %s AOCSCurrencyInfoList %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); + + currency_info->num_records = 0; + while (pos < seq_end && *pos != ASN1_INDEF_TERM) { + if (currency_info->num_records < ARRAY_LEN(currency_info->list)) { + ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); + ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); + ASN1_CALL(pos, rose_dec_qsig_AOCSCurrencyInfo(ctrl, "listEntry", tag, pos, + seq_end, ¤cy_info->list[currency_info->num_records])); + ++currency_info->num_records; + } else { + /* Too many records */ + return NULL; + } + } + + ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); + + return pos; +} + +/*! + * \internal + * \brief Decode the ChargingAssociation type. + * + * \param ctrl D channel controller for diagnostic messages or global options. + * \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 charging Parameter storage to fill. + * + * \retval Start of the next ASN.1 component on success. + * \retval NULL on error. + */ +static const unsigned char *rose_dec_qsig_AOC_ChargingAssociation(struct pri *ctrl, + const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end, + struct roseQsigAOCChargingAssociation *charging) +{ + int32_t value; + int length; + int explicit_offset; + const unsigned char *explicit_end; + + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " %s ChargingAssociation\n", name); + } + switch (tag) { + case ASN1_TYPE_INTEGER: + charging->type = 0; /* charge_identifier */ + ASN1_CALL(pos, asn1_dec_int(ctrl, "chargeIdentifier", tag, pos, end, &value)); + charging->id = value; + break; + case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 0: + charging->type = 1; /* charged_number */ + + /* 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, end, &length)); + ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, end); + + ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag)); + ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "chargedNumber", tag, pos, + explicit_end, &charging->number)); + + ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, end); + break; + default: + ASN1_DID_NOT_EXPECT_TAG(ctrl, tag); + return NULL; + } + + return pos; +} + +/*! + * \brief Decode the Q.SIG ChargeRequest 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_qsig_ChargeRequest_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; + int advice_offset; + const unsigned char *seq_end; + const unsigned char *advice_end; + struct roseQsigChargeRequestArg_ARG *charge_request; + + charge_request = &args->qsig.ChargeRequest; + + ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " ChargeRequest %s\n", asn1_tag2str(tag)); + } + ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); + ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); + + /* SEQUENCE SIZE(0..7) OF AdviceModeCombination */ + ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); + ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " adviceModeCombinations %s\n", asn1_tag2str(tag)); + } + ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length)); + ASN1_END_SETUP(advice_end, advice_offset, length, pos, seq_end); + + /* Decode SIZE(0..7) OF AdviceModeCombination */ + charge_request->num_records = 0; + while (pos < advice_end && *pos != ASN1_INDEF_TERM) { + if (charge_request->num_records < + ARRAY_LEN(charge_request->advice_mode_combinations)) { + ASN1_CALL(pos, asn1_dec_tag(pos, advice_end, &tag)); + ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED); + ASN1_CALL(pos, asn1_dec_int(ctrl, "adviceModeCombination", tag, pos, + advice_end, &value)); + charge_request->advice_mode_combinations[charge_request->num_records] = + value; + ++charge_request->num_records; + } else { + /* Too many records */ + return NULL; + } + } + + ASN1_END_FIXUP(ctrl, pos, advice_offset, advice_end, seq_end); + + /* Fixup will skip over any OPTIONAL manufacturer extension information */ + ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); + + return pos; +} + +/*! + * \brief Decode the Q.SIG ChargeRequest result 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_qsig_ChargeRequest_RES(struct pri *ctrl, unsigned tag, + const unsigned char *pos, const unsigned char *end, union rose_msg_result_args *args) +{ + int32_t value; + int length; + int seq_offset; + const unsigned char *seq_end; + struct roseQsigChargeRequestRes_RES *charge_request; + + charge_request = &args->qsig.ChargeRequest; + + ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " ChargeRequest %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_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED); + ASN1_CALL(pos, asn1_dec_int(ctrl, "adviceModeCombination", tag, pos, seq_end, + &value)); + charge_request->advice_mode_combination = value; + + /* Fixup will skip over any OPTIONAL manufacturer extension information */ + ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); + + return pos; +} + +/*! + * \brief Decode the Q.SIG AocFinal 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_qsig_AocFinal_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; + int specific_offset; + const unsigned char *seq_end; + const unsigned char *specific_end; + const unsigned char *save_pos; + struct roseQsigAocFinalArg_ARG *aoc_final; + + aoc_final = &args->qsig.AocFinal; + + ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " AocFinal %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)); + switch (tag) { + case ASN1_CLASS_CONTEXT_SPECIFIC | 0: + aoc_final->type = 0; /* charge_not_available */ + ASN1_CALL(pos, asn1_dec_null(ctrl, "chargeNotAvailable", tag, pos, seq_end)); + break; + case ASN1_CLASS_CONTEXT_SPECIFIC | 1: + aoc_final->type = 1; /* free_of_charge */ + ASN1_CALL(pos, asn1_dec_null(ctrl, "freeOfCharge", tag, pos, seq_end)); + break; + case ASN1_TAG_SEQUENCE: + aoc_final->type = 2; /* specific_currency */ + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " specificCurrency %s\n", asn1_tag2str(tag)); + } + ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); + ASN1_END_SETUP(specific_end, specific_offset, length, pos, seq_end); + + ASN1_CALL(pos, asn1_dec_tag(pos, specific_end, &tag)); + ASN1_CHECK_TAG(ctrl, tag, tag, + ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1); + ASN1_CALL(pos, rose_dec_qsig_AOC_RecordedCurrency(ctrl, "recordedCurrency", tag, + pos, specific_end, &aoc_final->specific.recorded)); + + if (pos < specific_end && *pos != ASN1_INDEF_TERM) { + ASN1_CALL(pos, asn1_dec_tag(pos, specific_end, &tag)); + ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 2); + ASN1_CALL(pos, asn1_dec_int(ctrl, "finalBillingId", tag, pos, specific_end, + &value)); + aoc_final->specific.billing_id = value; + aoc_final->specific.billing_id_present = 1; + } else { + aoc_final->specific.billing_id_present = 0; + } + + ASN1_END_FIXUP(ctrl, pos, specific_offset, specific_end, seq_end); + break; + default: + ASN1_DID_NOT_EXPECT_TAG(ctrl, tag); + return NULL; + } + + /* + * A sequence specifies an ordered list of component types. + * However, for simplicity we are not checking the order of + * the remaining optional components. + */ + aoc_final->charging_association_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 | 0: + case ASN1_TYPE_INTEGER: + ASN1_CALL(pos, rose_dec_qsig_AOC_ChargingAssociation(ctrl, + "chargingAssociation", tag, pos, seq_end, + &aoc_final->charging_association)); + aoc_final->charging_association_present = 1; + break; + case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1: + case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2: + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " finalArgExtension %s\n", asn1_tag2str(tag)); + } + /* Fixup will skip over the manufacturer extension information */ + default: + pos = save_pos; + goto cancel_options; + } + } +cancel_options:; + + ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); + + return pos; +} + +/*! + * \brief Decode the Q.SIG AocInterim 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_qsig_AocInterim_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; + int specific_offset; + const unsigned char *seq_end; + const unsigned char *specific_end; + struct roseQsigAocInterimArg_ARG *aoc_interim; + + aoc_interim = &args->qsig.AocInterim; + + ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " AocInterim %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)); + switch (tag) { + case ASN1_CLASS_CONTEXT_SPECIFIC | 0: + aoc_interim->type = 0; /* charge_not_available */ + ASN1_CALL(pos, asn1_dec_null(ctrl, "chargeNotAvailable", tag, pos, seq_end)); + break; + case ASN1_CLASS_CONTEXT_SPECIFIC | 1: + aoc_interim->type = 1; /* free_of_charge */ + ASN1_CALL(pos, asn1_dec_null(ctrl, "freeOfCharge", tag, pos, seq_end)); + break; + case ASN1_TAG_SEQUENCE: + aoc_interim->type = 2; /* specific_currency */ + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " specificCurrency %s\n", asn1_tag2str(tag)); + } + ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); + ASN1_END_SETUP(specific_end, specific_offset, length, pos, seq_end); + + ASN1_CALL(pos, asn1_dec_tag(pos, specific_end, &tag)); + ASN1_CHECK_TAG(ctrl, tag, tag, + ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1); + ASN1_CALL(pos, rose_dec_qsig_AOC_RecordedCurrency(ctrl, "recordedCurrency", tag, + pos, specific_end, &aoc_interim->specific.recorded)); + + if (pos < specific_end && *pos != ASN1_INDEF_TERM) { + ASN1_CALL(pos, asn1_dec_tag(pos, specific_end, &tag)); + ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 2); + ASN1_CALL(pos, asn1_dec_int(ctrl, "interimBillingId", tag, pos, specific_end, + &value)); + aoc_interim->specific.billing_id = value; + aoc_interim->specific.billing_id_present = 1; + } else { + aoc_interim->specific.billing_id_present = 0; + } + + ASN1_END_FIXUP(ctrl, pos, specific_offset, specific_end, seq_end); + break; + default: + ASN1_DID_NOT_EXPECT_TAG(ctrl, tag); + return NULL; + } + + /* Fixup will skip over any OPTIONAL manufacturer extension information */ + ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); + + return pos; +} + +/*! + * \brief Decode the Q.SIG AocRate 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_qsig_AocRate_ARG(struct pri *ctrl, unsigned tag, + const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args) +{ + int length; + int seq_offset; + const unsigned char *seq_end; + struct roseQsigAocRateArg_ARG *aoc_rate; + + aoc_rate = &args->qsig.AocRate; + + ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " AocRate %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)); + switch (tag) { + case ASN1_TYPE_NULL: + aoc_rate->type = 0; /* charge_not_available */ + ASN1_CALL(pos, asn1_dec_null(ctrl, "chargeNotAvailable", tag, pos, seq_end)); + break; + case ASN1_TAG_SEQUENCE: + aoc_rate->type = 1; /* currency_info_list */ + ASN1_CALL(pos, rose_dec_qsig_AOCSCurrencyInfoList(ctrl, "aocSCurrencyInfoList", + tag, pos, seq_end, &aoc_rate->currency_info)); + break; + default: + ASN1_DID_NOT_EXPECT_TAG(ctrl, tag); + return NULL; + } + + /* Fixup will skip over any OPTIONAL manufacturer extension information */ + ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); + + return pos; +} + +/*! + * \brief Decode the Q.SIG AocComplete 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_qsig_AocComplete_ARG(struct pri *ctrl, unsigned tag, + const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args) +{ + int length; + int seq_offset; + const unsigned char *seq_end; + const unsigned char *save_pos; + struct roseQsigAocCompleteArg_ARG *aoc_complete; + + aoc_complete = &args->qsig.AocComplete; + + ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " AocComplete %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, "chargedUser", tag, pos, seq_end, + &aoc_complete->charged_user_number)); + + /* + * A sequence specifies an ordered list of component types. + * However, for simplicity we are not checking the order of + * the remaining optional components. + */ + aoc_complete->charging_association_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 | 0: + case ASN1_TYPE_INTEGER: + ASN1_CALL(pos, rose_dec_qsig_AOC_ChargingAssociation(ctrl, + "chargingAssociation", tag, pos, seq_end, + &aoc_complete->charging_association)); + aoc_complete->charging_association_present = 1; + break; + case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1: + case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2: + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " completeArgExtension %s\n", asn1_tag2str(tag)); + } + /* Fixup will skip over the manufacturer extension information */ + default: + pos = save_pos; + goto cancel_options; + } + } +cancel_options:; + + ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); + + return pos; +} + +/*! + * \brief Decode the Q.SIG AocComplete result 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_qsig_AocComplete_RES(struct pri *ctrl, unsigned tag, + const unsigned char *pos, const unsigned char *end, union rose_msg_result_args *args) +{ + int32_t value; + int length; + int seq_offset; + const unsigned char *seq_end; + struct roseQsigAocCompleteRes_RES *aoc_complete; + + aoc_complete = &args->qsig.AocComplete; + + ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " AocComplete %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_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED); + ASN1_CALL(pos, asn1_dec_int(ctrl, "chargingOption", tag, pos, seq_end, &value)); + aoc_complete->charging_option = value; + + /* Fixup will skip over any OPTIONAL manufacturer extension information */ + ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); + + return pos; +} + +/*! + * \brief Decode the Q.SIG AocDivChargeReq 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_qsig_AocDivChargeReq_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 roseQsigAocDivChargeReqArg_ARG *aoc_div_charge_req; + + aoc_div_charge_req = &args->qsig.AocDivChargeReq; + + ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " AocDivChargeReq %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, "divertingUser", tag, pos, seq_end, + &aoc_div_charge_req->diverting_user_number)); + + ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); + switch (tag) { + case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 0: + case ASN1_TYPE_INTEGER: + ASN1_CALL(pos, rose_dec_qsig_AOC_ChargingAssociation(ctrl, "chargingAssociation", + tag, pos, seq_end, &aoc_div_charge_req->charging_association)); + aoc_div_charge_req->charging_association_present = 1; + + ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); + break; + default: + aoc_div_charge_req->charging_association_present = 0; + break; + } + + ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED); + ASN1_CALL(pos, asn1_dec_int(ctrl, "diversionType", tag, pos, seq_end, &value)); + aoc_div_charge_req->diversion_type = value; + + /* Fixup will skip over any OPTIONAL manufacturer extension information */ + ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); + + return pos; +} + +/* ------------------------------------------------------------------- */ +/* end rose_qsig_aoc.c */ diff --git a/rosetest.c b/rosetest.c index dd41eb5..3a66408 100644 --- a/rosetest.c +++ b/rosetest.c @@ -757,6 +757,316 @@ static const struct rose_message rose_qsig_msgs[] = { .component.invoke.args.qsig.CallingName.name.char_set = 1, }, + /* Q.SIG SS-AOC-Operations */ + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_QSIG_ChargeRequest, + .component.invoke.invoke_id = 11, + .component.invoke.args.qsig.ChargeRequest.num_records = 0, + }, + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_QSIG_ChargeRequest, + .component.invoke.invoke_id = 12, + .component.invoke.args.qsig.ChargeRequest.num_records = 1, + .component.invoke.args.qsig.ChargeRequest.advice_mode_combinations[0] = 3, + }, + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_QSIG_ChargeRequest, + .component.invoke.invoke_id = 13, + .component.invoke.args.qsig.ChargeRequest.num_records = 2, + .component.invoke.args.qsig.ChargeRequest.advice_mode_combinations[0] = 4, + .component.invoke.args.qsig.ChargeRequest.advice_mode_combinations[1] = 3, + }, + { + .type = ROSE_COMP_TYPE_RESULT, + .component.result.operation = ROSE_QSIG_ChargeRequest, + .component.result.invoke_id = 14, + .component.result.args.qsig.ChargeRequest.advice_mode_combination = 3, + }, + + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_QSIG_GetFinalCharge, + .component.invoke.invoke_id = 15, + }, + + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_QSIG_AocFinal, + .component.invoke.invoke_id = 16, + .component.invoke.args.qsig.AocFinal.type = 0, + }, + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_QSIG_AocFinal, + .component.invoke.invoke_id = 17, + .component.invoke.args.qsig.AocFinal.type = 1, + }, + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_QSIG_AocFinal, + .component.invoke.invoke_id = 18, + .component.invoke.args.qsig.AocFinal.type = 2, + .component.invoke.args.qsig.AocFinal.specific.recorded.amount.currency = 800, + .component.invoke.args.qsig.AocFinal.specific.recorded.amount.multiplier = 2, + .component.invoke.args.qsig.AocFinal.specific.recorded.currency = "Rupies", + }, + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_QSIG_AocFinal, + .component.invoke.invoke_id = 19, + .component.invoke.args.qsig.AocFinal.type = 2, + .component.invoke.args.qsig.AocFinal.specific.recorded.amount.currency = 800, + .component.invoke.args.qsig.AocFinal.specific.recorded.amount.multiplier = 2, + .component.invoke.args.qsig.AocFinal.specific.recorded.currency = "Rupies", + .component.invoke.args.qsig.AocFinal.specific.billing_id_present = 1, + .component.invoke.args.qsig.AocFinal.specific.billing_id = 2, + }, + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_QSIG_AocFinal, + .component.invoke.invoke_id = 20, + .component.invoke.args.qsig.AocFinal.type = 2, + .component.invoke.args.qsig.AocFinal.specific.recorded.amount.currency = 800, + .component.invoke.args.qsig.AocFinal.specific.recorded.amount.multiplier = 2, + .component.invoke.args.qsig.AocFinal.specific.recorded.currency = "Rupies", + .component.invoke.args.qsig.AocFinal.charging_association_present = 1, + .component.invoke.args.qsig.AocFinal.charging_association.type = 0, + .component.invoke.args.qsig.AocFinal.charging_association.id = 200, + }, + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_QSIG_AocFinal, + .component.invoke.invoke_id = 21, + .component.invoke.args.qsig.AocFinal.type = 2, + .component.invoke.args.qsig.AocFinal.specific.recorded.amount.currency = 800, + .component.invoke.args.qsig.AocFinal.specific.recorded.amount.multiplier = 2, + .component.invoke.args.qsig.AocFinal.specific.recorded.currency = "Rupies", + .component.invoke.args.qsig.AocFinal.specific.billing_id_present = 1, + .component.invoke.args.qsig.AocFinal.specific.billing_id = 2, + .component.invoke.args.qsig.AocFinal.charging_association_present = 1, + .component.invoke.args.qsig.AocFinal.charging_association.type = 0, + .component.invoke.args.qsig.AocFinal.charging_association.id = 200, + }, + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_QSIG_AocFinal, + .component.invoke.invoke_id = 22, + .component.invoke.args.qsig.AocFinal.type = 2, + .component.invoke.args.qsig.AocFinal.specific.recorded.amount.currency = 800, + .component.invoke.args.qsig.AocFinal.specific.recorded.amount.multiplier = 2, + .component.invoke.args.qsig.AocFinal.specific.recorded.currency = "Rupies", + .component.invoke.args.qsig.AocFinal.charging_association_present = 1, + .component.invoke.args.qsig.AocFinal.charging_association.type = 1, + .component.invoke.args.qsig.AocFinal.charging_association.number.plan = 4, + .component.invoke.args.qsig.AocFinal.charging_association.number.length = 4, + .component.invoke.args.qsig.AocFinal.charging_association.number.str = "1802", + }, + + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_QSIG_AocInterim, + .component.invoke.invoke_id = 23, + .component.invoke.args.qsig.AocInterim.type = 0, + }, + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_QSIG_AocInterim, + .component.invoke.invoke_id = 24, + .component.invoke.args.qsig.AocInterim.type = 1, + }, + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_QSIG_AocInterim, + .component.invoke.invoke_id = 25, + .component.invoke.args.qsig.AocInterim.type = 2, + .component.invoke.args.qsig.AocInterim.specific.recorded.amount.currency = 800, + .component.invoke.args.qsig.AocInterim.specific.recorded.amount.multiplier = 2, + .component.invoke.args.qsig.AocInterim.specific.recorded.currency = "Rupies", + }, + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_QSIG_AocInterim, + .component.invoke.invoke_id = 26, + .component.invoke.args.qsig.AocInterim.type = 2, + .component.invoke.args.qsig.AocInterim.specific.recorded.amount.currency = 800, + .component.invoke.args.qsig.AocInterim.specific.recorded.amount.multiplier = 2, + .component.invoke.args.qsig.AocInterim.specific.recorded.currency = "Rupies", + .component.invoke.args.qsig.AocInterim.specific.billing_id_present = 1, + .component.invoke.args.qsig.AocInterim.specific.billing_id = 2, + }, + + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_QSIG_AocRate, + .component.invoke.invoke_id = 27, + .component.invoke.args.qsig.AocRate.type = 0, + }, + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_QSIG_AocRate, + .component.invoke.invoke_id = 28, + .component.invoke.args.qsig.AocRate.type = 1, + .component.invoke.args.qsig.AocRate.currency_info.num_records = 1, + .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4, + .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 0, + .component.invoke.args.qsig.AocRate.currency_info.list[0].u.special_charging_code = 3, + }, + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_QSIG_AocRate, + .component.invoke.invoke_id = 29, + .component.invoke.args.qsig.AocRate.type = 1, + .component.invoke.args.qsig.AocRate.currency_info.num_records = 1, + .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4, + .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 1, + .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.currency = "Dollars", + .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.amount.currency = 7, + .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.amount.multiplier = 1, + .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.charging_type = 1, + .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.time.length = 8, + .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.time.scale = 4, + }, + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_QSIG_AocRate, + .component.invoke.invoke_id = 30, + .component.invoke.args.qsig.AocRate.type = 1, + .component.invoke.args.qsig.AocRate.currency_info.num_records = 1, + .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4, + .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 1, + .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.currency = "Dollars", + .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.amount.currency = 7, + .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.amount.multiplier = 1, + .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.charging_type = 1, + .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.time.length = 8, + .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.time.scale = 4, + .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.granularity_present = 1, + .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.granularity.length = 20, + .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.granularity.scale = 3, + }, + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_QSIG_AocRate, + .component.invoke.invoke_id = 31, + .component.invoke.args.qsig.AocRate.type = 1, + .component.invoke.args.qsig.AocRate.currency_info.num_records = 1, + .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4, + .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 2, + .component.invoke.args.qsig.AocRate.currency_info.list[0].u.flat_rate.currency = "Euros", + .component.invoke.args.qsig.AocRate.currency_info.list[0].u.flat_rate.amount.currency = 4, + .component.invoke.args.qsig.AocRate.currency_info.list[0].u.flat_rate.amount.multiplier = 1, + }, + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_QSIG_AocRate, + .component.invoke.invoke_id = 32, + .component.invoke.args.qsig.AocRate.type = 1, + .component.invoke.args.qsig.AocRate.currency_info.num_records = 1, + .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4, + .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 3, + .component.invoke.args.qsig.AocRate.currency_info.list[0].u.volume_rate.currency = "Yen", + .component.invoke.args.qsig.AocRate.currency_info.list[0].u.volume_rate.amount.currency = 300, + .component.invoke.args.qsig.AocRate.currency_info.list[0].u.volume_rate.amount.multiplier = 5, + .component.invoke.args.qsig.AocRate.currency_info.list[0].u.volume_rate.unit = 2, + }, + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_QSIG_AocRate, + .component.invoke.invoke_id = 33, + .component.invoke.args.qsig.AocRate.type = 1, + .component.invoke.args.qsig.AocRate.currency_info.num_records = 2, + .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4, + .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 2, + .component.invoke.args.qsig.AocRate.currency_info.list[0].u.flat_rate.currency = "Euros", + .component.invoke.args.qsig.AocRate.currency_info.list[0].u.flat_rate.amount.currency = 4, + .component.invoke.args.qsig.AocRate.currency_info.list[0].u.flat_rate.amount.multiplier = 1, + .component.invoke.args.qsig.AocRate.currency_info.list[1].charged_item = 4, + .component.invoke.args.qsig.AocRate.currency_info.list[1].currency_type = 3, + .component.invoke.args.qsig.AocRate.currency_info.list[1].u.volume_rate.currency = "Yen", + .component.invoke.args.qsig.AocRate.currency_info.list[1].u.volume_rate.amount.currency = 300, + .component.invoke.args.qsig.AocRate.currency_info.list[1].u.volume_rate.amount.multiplier = 5, + .component.invoke.args.qsig.AocRate.currency_info.list[1].u.volume_rate.unit = 2, + }, + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_QSIG_AocRate, + .component.invoke.invoke_id = 34, + .component.invoke.args.qsig.AocRate.type = 1, + .component.invoke.args.qsig.AocRate.currency_info.num_records = 1, + .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4, + .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 4, + }, + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_QSIG_AocRate, + .component.invoke.invoke_id = 35, + .component.invoke.args.qsig.AocRate.type = 1, + .component.invoke.args.qsig.AocRate.currency_info.num_records = 1, + .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4, + .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 5, + }, + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_QSIG_AocRate, + .component.invoke.invoke_id = 36, + .component.invoke.args.qsig.AocRate.type = 1, + .component.invoke.args.qsig.AocRate.currency_info.num_records = 1, + .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4, + .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 6, + }, + + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_QSIG_AocComplete, + .component.invoke.invoke_id = 37, + .component.invoke.args.qsig.AocComplete.charged_user_number.plan = 4, + .component.invoke.args.qsig.AocComplete.charged_user_number.length = 4, + .component.invoke.args.qsig.AocComplete.charged_user_number.str = "8340", + }, + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_QSIG_AocComplete, + .component.invoke.invoke_id = 38, + .component.invoke.args.qsig.AocComplete.charged_user_number.plan = 4, + .component.invoke.args.qsig.AocComplete.charged_user_number.length = 4, + .component.invoke.args.qsig.AocComplete.charged_user_number.str = "8340", + .component.invoke.args.qsig.AocComplete.charging_association_present = 1, + .component.invoke.args.qsig.AocComplete.charging_association.type = 0, + .component.invoke.args.qsig.AocComplete.charging_association.id = 8298, + }, + + { + .type = ROSE_COMP_TYPE_RESULT, + .component.result.operation = ROSE_QSIG_AocComplete, + .component.result.invoke_id = 39, + .component.result.args.qsig.AocComplete.charging_option = 2, + }, + + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_QSIG_AocDivChargeReq, + .component.invoke.invoke_id = 40, + .component.invoke.args.qsig.AocDivChargeReq.diverting_user_number.plan = 4, + .component.invoke.args.qsig.AocDivChargeReq.diverting_user_number.length = 4, + .component.invoke.args.qsig.AocDivChargeReq.diverting_user_number.str = "8340", + .component.invoke.args.qsig.AocDivChargeReq.diversion_type = 3, + }, + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_QSIG_AocDivChargeReq, + .component.invoke.invoke_id = 41, + .component.invoke.args.qsig.AocDivChargeReq.diverting_user_number.plan = 4, + .component.invoke.args.qsig.AocDivChargeReq.diverting_user_number.length = 4, + .component.invoke.args.qsig.AocDivChargeReq.diverting_user_number.str = "8340", + .component.invoke.args.qsig.AocDivChargeReq.charging_association_present = 1, + .component.invoke.args.qsig.AocDivChargeReq.charging_association.type = 0, + .component.invoke.args.qsig.AocDivChargeReq.charging_association.id = 8298, + .component.invoke.args.qsig.AocDivChargeReq.diversion_type = 3, + }, + /* Q.SIG Call-Transfer-Operations (CT) */ { .type = ROSE_COMP_TYPE_INVOKE, @@ -1697,6 +2007,8 @@ int main(int argc, char *argv[]) pri_message(&dummy_ctrl, "\n"); pri_message(&dummy_ctrl, "sizeof(struct roseQsigCallRerouting_ARG) = %u\n", (unsigned) sizeof(struct roseQsigCallRerouting_ARG)); + pri_message(&dummy_ctrl, "sizeof(struct roseQsigAocRateArg_ARG) = %u\n", + (unsigned) sizeof(struct roseQsigAocRateArg_ARG)); pri_message(&dummy_ctrl, "sizeof(struct roseQsigMWIInterrogateRes) = %u\n", (unsigned) sizeof(struct roseQsigMWIInterrogateRes));