/* * fac.c * * Copyright (C) 2006, Nadi Sarrar * Nadi Sarrar * * Portions of this file are based on the mISDN sources * by Karsten Keil. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "asn1.h" #include "diversion.h" #include #include "ccbs.h" #include "ect.h" #include "3pty.h" #include #define AOC_MAX_NUM_CHARGE_UNITS 0xFFFFFF #define AOCE_CHARGE_UNIT_IE_LENGTH 17 #define AOCD_CHARGE_UNIT_IE_LENGTH 20 enum { SUPPLEMENTARY_SERVICE = 0x91, /* remote operations protocol */ } SERVICE_DISCRIMINATOR; /* ******************************************************************* */ /*! * \brief Encode the head of the Facility component message. * * \param p Start of the Facility message * \param componentType Component-Type value * * \return Position for the next octet in the message */ __u8 *encodeComponent_Head(__u8 * p, enum asn1ComponentTag componentTag) { *p++ = IE_FACILITY; /* Facility IE identifier */ *p++ = 0; /* length -- not known yet */ *p++ = SUPPLEMENTARY_SERVICE; /* remote operations protocol */ *p++ = componentTag; *p++ = 0; /* length -- not known yet */ return p; } /* end encodeComponent_Head() */ /* ******************************************************************* */ /*! * \brief Encode the head of the Facility component message * with a length that can take a full __u8 value. * * \param p Start of the Facility message * \param componentType Component-Type value * * \return Position for the next octet in the message */ __u8 *encodeComponent_Head_Long_u8(__u8 * p, enum asn1ComponentTag componentTag) { *p++ = IE_FACILITY; /* Facility IE identifier */ *p++ = 0; /* length -- not known yet */ *p++ = SUPPLEMENTARY_SERVICE; /* remote operations protocol */ *p++ = componentTag; p += ASN1_NUM_OCTETS_LONG_LENGTH_u8; /* length -- not known yet */ return p; } /* end encodeComponent_Head_Long_u8() */ /* ******************************************************************* */ /*! * \brief Fill in the final length for the Facility IE contents. * * \param msg Beginning of the Facility IE contents. * \param p Pointer to the next octet of the Facility IE * contents if there were more. * * \return Length of the Facility IE message */ int encodeComponent_Length(__u8 * msg, __u8 * p) { msg[4] = p - &msg[5]; msg[1] = p - &msg[2]; return msg[1] + 2; } /* end encodeComponent_Length() */ /* ******************************************************************* */ /*! * \brief Fill in the final length for the Facility IE contents * with a length that can take a full __u8 value. * * \param msg Beginning of the Facility IE contents. * \param p Pointer to the next octet of the Facility IE * contents if there were more. * * \return Length of the Facility IE message */ int encodeComponent_Length_Long_u8(__u8 * msg, __u8 * p) { encodeLen_Long_u8(&msg[4], p - &msg[4 + ASN1_NUM_OCTETS_LONG_LENGTH_u8]); msg[1] = p - &msg[2]; return msg[1] + 2; } /* end encodeComponent_Length_Long_u8() */ /* ******************************************************************* */ /*! * \brief Encode the Facility ie component operation-value. * * \param dest Where to put the operation-value * \param operationValue enum operation-value to encode * * \return Length of the operation-value */ int encodeOperationValue(__u8 * dest, int operationValue) { struct asn1Oid operationOid; if (IsEnumOid(operationValue) && ConvertEnumToOid(&operationOid, operationValue)) { return encodeOid(dest, ASN1_TAG_OBJECT_IDENTIFIER, &operationOid); } else { return encodeInt(dest, ASN1_TAG_INTEGER, operationValue); } } /* end encodeOperationValue() */ /* ******************************************************************* */ /*! * \brief Encode the Facility ie component error-value. * * \param dest Where to put the error-value * \param errorValue enum error-value to encode * * \return Length of the error-value */ int encodeErrorValue(__u8 * dest, int errorValue) { return encodeOperationValue(dest, errorValue); } /* end encodeErrorValue() */ /* ******************************************************************* */ /*! * \brief Encode the common invoke component beginning * * \param Dest Where to put the encoding * \param InvokeID * \param OperationValue * * \return Position for the next octet in the message */ __u8 *encodeComponentInvoke_Head(__u8 * Dest, int InvokeID, enum Operation OperationValue) { __u8 *p; p = encodeComponent_Head(Dest, asn1ComponentTag_Invoke); p += encodeInt(p, ASN1_TAG_INTEGER, InvokeID); //p += encodeInt(p, ASN1_TAG_CONTEXT_SPECIFIC | 0, LinkedID); /* Optional */ p += encodeOperationValue(p, OperationValue); return p; } /* end encodeComponentInvoke_Head() */ /* ******************************************************************* */ /*! * \brief Encode the common invoke component beginning * with a length that can take a full __u8 value. * * \param Dest Where to put the encoding * \param InvokeID * \param OperationValue * * \return Position for the next octet in the message */ __u8 *encodeComponentInvoke_Head_Long_u8(__u8 * Dest, int InvokeID, enum Operation OperationValue) { __u8 *p; p = encodeComponent_Head_Long_u8(Dest, asn1ComponentTag_Invoke); p += encodeInt(p, ASN1_TAG_INTEGER, InvokeID); //p += encodeInt(p, ASN1_TAG_CONTEXT_SPECIFIC | 0, LinkedID); /* Optional */ p += encodeOperationValue(p, OperationValue); return p; } /* end encodeComponentInvoke_Head_Long_u8() */ static int encodeAOCDChargingUnitOperation(__u8 * dest, const struct asn1_parm *pc, int numberOfUnits) { /* Manually encoded ASN.1 */ unsigned char len = 0; int i = 0; int result = -1; __u8 *p = dest; if ((p != NULL) && (numberOfUnits <= AOC_MAX_NUM_CHARGE_UNITS)) { if (numberOfUnits > 0xFFFF) len = 3; else if (numberOfUnits > 0xFF) len = 2; else len = 1; p[i++] = IE_FACILITY; // IE identifier p[i++] = 0x00; // length -- not known yet p[i++] = SUPPLEMENTARY_SERVICE; // remote operations protocol p[i++] = 0xa1; // invoke component p[i++] = 0x00; // length -- not known yet p[i++] = 0x02; // Invoke ID p[i++] = 0x01; // InvokeId Length p[i++] = pc->u.inv.invokeId; p[i++] = 0x02; // Operation Tag p[i++] = 0x01; // Tag Length p[i++] = Fac_AOCDChargingUnit; // Operation Value p[i++] = 0x30; p[i++] = (0x09 + len); // Length p[i++] = 0xa1; // APDU p[i++] = (0x04 + len); // Length p[i++] = 0x30; p[i++] = (0x02 + len); p[i++] = 0x02; // Operation Tag p[i++] = 0x01; // AOC-D so Sub-Total // Recorded units could take up as much as 3 bytes (0xFFFFFF) p[i] = numberOfUnits & 0xFF; if (len > 1) p[i+1] = (numberOfUnits >> 8) & 0xFF; if (len > 2) p[i+2] = (numberOfUnits >> 16) & 0xFF; i += len; p[i++] = 0x82; p[i++] = 0x01; p[i++] = 0x01; p[1] = (AOCD_CHARGE_UNIT_IE_LENGTH + len); // IE Payload Length p[4] = p[1] - 3; // Invoke Component Length result = p[1] + 2; // Total Length of IE } return result; } static int encodeAOCEChargingUnitOperation(__u8 * dest, const struct asn1_parm *pc, int numberOfUnits) { /* Manually encoded ASN.1 */ unsigned char len = 0; int i = 0; int result = -1; __u8 *p = dest; if ((p != NULL) && (numberOfUnits <= AOC_MAX_NUM_CHARGE_UNITS)) { if (numberOfUnits > 0xFFFF) len = 3; else if (numberOfUnits > 0xFF) len = 2; else len = 1; p[i++] = IE_FACILITY; // IE identifier p[i++] = 0x00; // length -- not known yet p[i++] = SUPPLEMENTARY_SERVICE; // remote operations protocol p[i++] = 0xa1; // invoke component p[i++] = 0x00; // length -- not known yet p[i++] = 0x02; // Invoke ID p[i++] = 0x01; // InvokeId Length p[i++] = pc->u.inv.invokeId; p[i++] = 0x02; // Operation Tag p[i++] = 0x01; // Tag Length p[i++] = Fac_AOCEChargingUnit; // Operation Value p[i++] = 0xa1; // APDU p[i++] = 0x30; p[i++] = (0x09 + len); // Length p[i++] = 0xa1; // APDU p[i++] = (0x04 + len); // Length p[i++] = 0x30; p[i++] = (0x02 + len); p[i++] = 0x02; p[i++] = 0x02; // AOC-E so Total // Recorded units could take up as much as 3 bytes (0xFFFFFF) p[i] = numberOfUnits & 0xFF; if (len > 1) p[i+1] = (numberOfUnits >> 8) & 0xFF; if (len > 2) p[i+2] = (numberOfUnits >> 16) & 0xFF; i += len; p[1] = (AOCE_CHARGE_UNIT_IE_LENGTH + len); // IE Payload Length p[4] = p[1] - 3; // Invoke Component Length result = p[1] + 2; // Total Length of IE } return result; } static int encodeFacMcidIvokeRequest(__u8 * dest, const struct asn1_parm *pc) { int i = 0; int result = -1; __u8 *p = dest; if (p != NULL) { p[i++] = IE_FACILITY; // IE identifier p[i++] = 0x09; // length p[i++] = SUPPLEMENTARY_SERVICE; // remote operations protocol p[i++] = 0xa1; // invoke component p[i++] = 0x06; // Manually Encoding the MCID p[i++] = 0x02; // Invoke ID p[i++] = 0x01; // InvokeId Length p[i++] = pc->u.inv.invokeId; // Invoke value p[i++] = 0x02; // Operation Tag p[i++] = 0x01; // Tag Length p[i++] = Fac_MaliciousCallId; // Operation Value result = p[1] + 2; // Total IE Length } return result; } #if 0 case Fac_RESULT: len = encodeFacRESULT(dest, pc, &inv->o.RESULT); break; case Fac_ERROR: len = encodeFacERROR(dest, pc, &inv->o.ERROR); break; case Fac_REJECT: len = encodeFacREJECT(dest, pc, &inv->o.REJECT); break; #endif /* * Facility IE Encoding */ static int encodeFacReturnResult(__u8 * dest, const struct asn1_parm *pc) { const struct asn1ReturnResult *res = &pc->u.retResult; int len = -1; char ops[20]; __u8 *p; if (res->operationValuePresent) sprintf(ops,"operation 0x%04x", res->operationValue); else sprintf(ops, "no operation value"); dprint(DBGM_ASN1_ENC, "Return result %s Id:%d start encoding\n", ops, res->invokeId); if (res->operationValuePresent) { switch (res->operationValue) { case Fac_Begin3PTY: len = encodeFacBegin3PTY(dest, pc, NULL); break; case Fac_End3PTY: len = encodeFacEnd3PTY(dest, pc, NULL); break; case Fac_StatusRequest: len = encodeFacStatusRequest(dest, pc, NULL); break; case Fac_CCBSStatusRequest: len = encodeFacCCBSStatusRequest(dest, pc, NULL); break; case Fac_CCBSRequest: len = encodeFacCCBSRequest(dest, pc, NULL); break; case Fac_CCBSInterrogate: len = encodeFacCCBSInterrogate(dest, pc, NULL); break; case Fac_CCNRRequest: len = encodeFacCCNRRequest(dest, pc, NULL); break; case Fac_CCNRInterrogate: len = encodeFacCCNRInterrogate(dest, pc, NULL); break; case Fac_CCBS_T_Request: len = encodeFacCCBS_T_Request(dest, pc, NULL); break; case Fac_CCNR_T_Request: len = encodeFacCCNR_T_Request(dest, pc, NULL); break; case Fac_EctLinkIdRequest: len = encodeFacEctLinkIdRequest(dest, pc, NULL); break; case Fac_EctLoopTest: len = encodeFacEctLoopTest(dest, pc, NULL); break; case Fac_InterrogationDiversion: len = encodeFacInterrogationDiversion(dest, pc, NULL); break; case Fac_InterrogateServedUserNumbers: len = encodeFacInterrogateServedUserNumbers(dest, pc, &res->o.InterrogateServedUserNumbers); break; default: eprint("ReturnResult Function %s not supported yet\n", ops); return -1; } } else { p = encodeComponent_Head(dest, asn1ComponentTag_Result); p += encodeInt(p, ASN1_TAG_INTEGER, res->invokeId); len = encodeComponent_Length(dest, p); } if (len < 0) eprint("Error on encoding ReturnResult %s\n", ops); else { dprint(DBGM_ASN1_ENC, "ReturnResult %s encoded in %d bytes\n", ops, len); dhexprint(DBGM_ASN1_DATA, "Facility:", dest, len); } return len; } /* ******************************************************************* */ /*! * \internal * \brief Encode the ERROR response. * * \param dest Where to put the encoding * \param error ERROR parameters * * \return Length of the encoding */ static int encodeFacReturnError(__u8 * dest, const struct asn1_parm *pc) { __u8 *p; const struct asn1ReturnError *err = &pc->u.retError; int len = -1; dprint(DBGM_ASN1_ENC, "Return error Id:%d errorValue 0x%x start encoding\n", err->invokeId, err->errorValue); p = encodeComponent_Head(dest, asn1ComponentTag_Error); p += encodeInt(p, ASN1_TAG_INTEGER, err->invokeId); p += encodeErrorValue(p, err->errorValue); len = encodeComponent_Length(dest, p); dprint(DBGM_ASN1_ENC, "ReturnError encoded in %d bytes\n", len); dhexprint(DBGM_ASN1_DATA, "Facility:", dest, len); return len; } /* ******************************************************************* */ /*! * \internal * \brief Encode the REJECT response. * * \param dest Where to put the encoding * \param error REJECT parameters * * \return Length of the encoding */ static int encodeFacReject(__u8 * dest, const struct asn1_parm *pc) { const struct asn1Reject *rej = &pc->u.reject; int len = -1; char ids[16]; __u8 *p; if (rej->invokeIdPresent) sprintf(ids,"ID 0x%04x", rej->invokeId); else sprintf(ids, "no invoke ID"); dprint(DBGM_ASN1_ENC, "Reject %s problem %d value 0x%x start encoding\n", ids, rej->problem, rej->problemValue); p = encodeComponent_Head(dest, asn1ComponentTag_Reject); if (rej->invokeIdPresent) p += encodeInt(p, ASN1_TAG_INTEGER, rej->invokeId); else p += encodeNull(p, ASN1_TAG_NULL); p += encodeInt(p, ASN1_TAG_CONTEXT_SPECIFIC | rej->problem, rej->problemValue); len = encodeComponent_Length(dest, p); dprint(DBGM_ASN1_ENC, "Reject encoded in %d bytes\n", len); dhexprint(DBGM_ASN1_DATA, "Facility:", dest, len); return len; } static int encodeFacInvoke(__u8 * dest, const struct asn1_parm *pc) { const struct asn1Invoke *inv = &pc->u.inv; int len = -1; dprint(DBGM_ASN1_ENC, "Invoke operation 0x%x Id:%d start encoding\n", inv->operationValue, inv->invokeId); switch (inv->operationValue) { case Fac_None: break; /* Diversion support */ case Fac_ActivationDiversion: len = encodeFacActivationDiversion(dest, pc, &inv->o.ActivationDiversion); break; case Fac_Begin3PTY: len = encodeFacBegin3PTY(dest, pc, NULL); break; case Fac_End3PTY: len = encodeFacEnd3PTY(dest, pc, NULL); break; case Fac_DeactivationDiversion: len = encodeFacDeactivationDiversion(dest, pc, &inv->o.DeactivationDiversion); break; case Fac_ActivationStatusNotificationDiv: len = encodeFacActivationStatusNotificationDiv(dest, pc, &inv->o.ActivationStatusNotificationDiv); break; case Fac_DeactivationStatusNotificationDiv: len = encodeFacDeactivationStatusNotificationDiv(dest, pc, &inv->o.DeactivationStatusNotificationDiv); break; case Fac_InterrogationDiversion: len = encodeFacInterrogationDiversion(dest, pc, &inv->o.InterrogationDiversion); break; case Fac_DiversionInformation: len = encodeFacDiversionInformation(dest, pc, &inv->o.DiversionInformation); break; case Fac_CallDeflection: len = encodeFacCallDeflection(dest, pc, &inv->o.CallDeflection); break; case Fac_CallRerouteing: len = encodeFacCallRerouteing(dest, pc, &inv->o.CallRerouteing); break; case Fac_InterrogateServedUserNumbers: len = encodeFacInterrogateServedUserNumbers(dest, pc, NULL); break; case Fac_DivertingLegInformation1: len = encodeFacDivertingLegInformation1(dest, pc, &inv->o.DivertingLegInformation1); break; case Fac_DivertingLegInformation2: len = encodeFacDivertingLegInformation2(dest, pc, &inv->o.DivertingLegInformation2); break; case Fac_DivertingLegInformation3: len = encodeFacDivertingLegInformation3(dest, pc, &inv->o.DivertingLegInformation3); break; /* ECT support */ case Fac_EctExecute: len = encodeFacEctExecute(dest, pc, NULL); break; case Fac_ExplicitEctExecute: len = encodeFacExplicitEctExecute(dest, pc, &inv->o.ExplicitEctExecute); break; case Fac_RequestSubaddress: len = encodeFacRequestSubaddress(dest, pc, NULL); break; case Fac_SubaddressTransfer: len = encodeFacSubaddressTransfer(dest, pc, &inv->o.SubaddressTransfer); break; case Fac_EctLinkIdRequest: len = encodeFacEctLinkIdRequest(dest, pc, NULL); break; case Fac_EctInform: len = encodeFacEctInform(dest, pc, &inv->o.EctInform); break; case Fac_EctLoopTest: len = encodeFacEctLoopTest(dest, pc, &inv->o.EctLoopTest); break; /* AOC support */ case Fac_ChargingRequest: case Fac_AOCSCurrency: case Fac_AOCSSpecialArr: case Fac_AOCDCurrency: case Fac_AOCECurrency: break; case Fac_AOCDChargingUnit: len = encodeAOCDChargingUnitOperation(dest, pc, inv->o.AOCchu.recordedUnits); break; case Fac_AOCEChargingUnit: len = encodeAOCEChargingUnitOperation(dest, pc, inv->o.AOCchu.recordedUnits); break; /* Malicious Call Tag Support */ case Fac_MaliciousCallId: len = encodeFacMcidIvokeRequest(dest, pc); break; case Fac_StatusRequest: len = encodeFacStatusRequest(dest, pc, &inv->o.StatusRequest); break; /* CCBS/CCNR support */ case Fac_CallInfoRetain: len = encodeFacCallInfoRetain(dest, pc, &inv->o.CallInfoRetain); break; case Fac_EraseCallLinkageID: len = encodeFacEraseCallLinkageID(dest, pc, &inv->o.EraseCallLinkageID); break; case Fac_CCBSDeactivate: len = encodeFacCCBSDeactivate(dest, pc, &inv->o.CCBSDeactivate); break; case Fac_CCBSErase: len = encodeFacCCBSErase(dest, pc, &inv->o.CCBSErase); break; case Fac_CCBSRemoteUserFree: len = encodeFacCCBSRemoteUserFree(dest, pc, &inv->o.CCBSRemoteUserFree); break; case Fac_CCBSCall: len = encodeFacCCBSCall(dest, pc, &inv->o.CCBSCall); break; case Fac_CCBSStatusRequest: len = encodeFacCCBSStatusRequest(dest, pc, &inv->o.CCBSStatusRequest); break; case Fac_CCBSBFree: len = encodeFacCCBSBFree(dest, pc, &inv->o.CCBSBFree); break; case Fac_CCBSStopAlerting: len = encodeFacCCBSStopAlerting(dest, pc, &inv->o.CCBSStopAlerting); break; case Fac_CCBSRequest: len = encodeFacCCBSRequest(dest, pc, &inv->o.CCBSRequest); break; case Fac_CCBSInterrogate: len = encodeFacCCBSInterrogate(dest, pc, &inv->o.CCBSInterrogate); break; case Fac_CCNRRequest: len = encodeFacCCNRRequest(dest, pc, &inv->o.CCNRRequest); break; case Fac_CCNRInterrogate: len = encodeFacCCNRInterrogate(dest, pc, &inv->o.CCNRInterrogate); break; /* CCBS-T/CCNR-T support */ case Fac_CCBS_T_Call: len = encodeFacCCBS_T_Call(dest, pc, NULL); break; case Fac_CCBS_T_Suspend: len = encodeFacCCBS_T_Suspend(dest, pc, NULL); break; case Fac_CCBS_T_Resume: len = encodeFacCCBS_T_Resume(dest, pc, NULL); break; case Fac_CCBS_T_RemoteUserFree: len = encodeFacCCBS_T_RemoteUserFree(dest, pc, NULL); break; case Fac_CCBS_T_Available: len = encodeFacCCBS_T_Available(dest, pc, NULL); break; case Fac_CCBS_T_Request: len = encodeFacCCBS_T_Request(dest, pc, &inv->o.CCBS_T_Request); break; case Fac_CCNR_T_Request: len = encodeFacCCNR_T_Request(dest, pc, &inv->o.CCNR_T_Request); break; default: eprint("Function %d not supported yet\n", inv->operationValue); return -1; } if (len < 0) eprint("Error on encoding function 0x%x\n", inv->operationValue); else { dprint(DBGM_ASN1_ENC, "Function 0x%x encoded in %d bytes\n", inv->operationValue, len); dhexprint(DBGM_ASN1_DATA, "Facility:", dest, len); } return len; } int encodeFac(__u8 * dest, struct asn1_parm *ap) { int len = -1; if (ap->Valid) { switch (ap->comp) { case CompInvoke: len = encodeFacInvoke(dest, ap); break; case CompReturnResult: len = encodeFacReturnResult(dest, ap); break; case CompReturnError: len = encodeFacReturnError(dest, ap); break; case CompReject: len = encodeFacReject(dest, ap); break; default: eprint("Unknown component 0x%x\n", ap->comp); break; } } else eprint("Facility struct component(%d) not marked as valid\n", ap->comp); return len; } /* * Facility IE Decoding */ int decodeFac(__u8 * src, struct asn1_parm *ap) { unsigned fac_len; __u8 *end; __u8 *p = src; if (!p) { goto _dec_err; } fac_len = *p++; end = p + fac_len; if (*p++ != SUPPLEMENTARY_SERVICE) { goto _dec_err; } memset(ap, 0, sizeof(*ap)); if (ParseComponent(ap, p, end) == -1) { goto _dec_err; } switch (ap->comp) { case CompInvoke: switch (ap->u.inv.operationValue) { /* Diversion support */ case Fac_ActivationDiversion: case Fac_DeactivationDiversion: case Fac_ActivationStatusNotificationDiv: case Fac_DeactivationStatusNotificationDiv: case Fac_InterrogationDiversion: case Fac_DiversionInformation: case Fac_CallDeflection: case Fac_CallRerouteing: case Fac_InterrogateServedUserNumbers: case Fac_DivertingLegInformation1: case Fac_DivertingLegInformation2: case Fac_DivertingLegInformation3: /* ECT support */ case Fac_EctExecute: case Fac_ExplicitEctExecute: case Fac_RequestSubaddress: case Fac_SubaddressTransfer: case Fac_EctLinkIdRequest: case Fac_EctInform: case Fac_EctLoopTest: /* AOC support */ case Fac_AOCDCurrency: case Fac_AOCECurrency: case Fac_AOCDChargingUnit: case Fac_AOCEChargingUnit: case Fac_StatusRequest: /* CCBS/CCNR support */ case Fac_CallInfoRetain: case Fac_EraseCallLinkageID: case Fac_CCBSDeactivate: case Fac_CCBSErase: case Fac_CCBSRemoteUserFree: case Fac_CCBSCall: case Fac_CCBSStatusRequest: case Fac_CCBSBFree: case Fac_CCBSStopAlerting: case Fac_CCBSRequest: case Fac_CCBSInterrogate: case Fac_CCNRRequest: case Fac_CCNRInterrogate: /* CCBS-T/CCNR-T support */ case Fac_CCBS_T_Call: case Fac_CCBS_T_Suspend: case Fac_CCBS_T_Resume: case Fac_CCBS_T_RemoteUserFree: case Fac_CCBS_T_Available: case Fac_CCBS_T_Request: case Fac_CCNR_T_Request: ap->Valid = 1; return 0; default: eprint("Unknown invoke operation %x\n", ap->u.inv.operationValue); break; } break; /* ------------------------------------------------------------------- */ case CompReturnResult: if (!ap->u.retResult.operationValuePresent) { return 0; } switch (ap->u.retResult.operationValue) { /* Diversion support */ case Fac_ActivationDiversion: case Fac_DeactivationDiversion: case Fac_InterrogationDiversion: case Fac_CallDeflection: case Fac_CallRerouteing: case Fac_InterrogateServedUserNumbers: ap->Valid = 1; return 0; case Fac_ActivationStatusNotificationDiv: case Fac_DeactivationStatusNotificationDiv: case Fac_DiversionInformation: case Fac_DivertingLegInformation1: case Fac_DivertingLegInformation2: case Fac_DivertingLegInformation3: break; /* ECT support */ case Fac_EctExecute: case Fac_ExplicitEctExecute: case Fac_RequestSubaddress: case Fac_SubaddressTransfer: break; case Fac_EctLinkIdRequest: return 0; case Fac_EctInform: break; case Fac_EctLoopTest: return 0; /* AOC support */ case Fac_ChargingRequest: case Fac_AOCSCurrency: case Fac_AOCSSpecialArr: case Fac_AOCDCurrency: case Fac_AOCDChargingUnit: case Fac_AOCECurrency: case Fac_AOCEChargingUnit: break; case Fac_StatusRequest: return 0; /* CCBS/CCNR support */ case Fac_CallInfoRetain: case Fac_EraseCallLinkageID: break; case Fac_CCBSDeactivate: return 0; case Fac_CCBSErase: case Fac_CCBSRemoteUserFree: case Fac_CCBSCall: break; case Fac_CCBSStatusRequest: return 0; case Fac_CCBSBFree: case Fac_CCBSStopAlerting: break; case Fac_CCBSRequest: case Fac_CCBSInterrogate: case Fac_CCNRRequest: case Fac_CCNRInterrogate: return 0; /* CCBS-T/CCNR-T support */ case Fac_CCBS_T_Call: case Fac_CCBS_T_Suspend: case Fac_CCBS_T_Resume: case Fac_CCBS_T_RemoteUserFree: case Fac_CCBS_T_Available: break; case Fac_CCBS_T_Request: case Fac_CCNR_T_Request: return 0; default: break; } /* end switch */ break; /* ------------------------------------------------------------------- */ case CompReturnError: ap->Valid = 1; return 0; /* ------------------------------------------------------------------- */ case CompReject: ap->Valid = 1; return 0; } /* end switch */ _dec_err: return -1; } /* end decodeFac() */