Merging Advice of Charge code into libpri (bug #3843)
git-svn-id: https://origsvn.digium.com/svn/libpri/trunk@206 2fbb986a-6c06-0410-b554-c9c1f0a7f128
This commit is contained in:
parent
241f97782c
commit
240cd3ece0
6
libpri.h
6
libpri.h
@ -37,7 +37,8 @@
|
||||
#define PRI_DEBUG_Q931_DUMP (1 << 5) /* Show interpreted Q.931 frames */
|
||||
#define PRI_DEBUG_Q931_STATE (1 << 6) /* Debug Q.931 state machine changes */
|
||||
#define PRI_DEBUG_Q931_ANOMALY (1 << 7) /* Show unexpected events */
|
||||
#define PRI_DEBUG_APDU (1 << 8) /* Debug of APDU components such as ROSE */
|
||||
#define PRI_DEBUG_APDU (1 << 8) /* Debug of APDU components such as ROSE */
|
||||
#define PRI_DEBUG_AOC (1 << 9) /* Debug of Advice of Charge ROSE Messages */
|
||||
|
||||
#define PRI_DEBUG_ALL (0xffff) /* Everything */
|
||||
|
||||
@ -53,7 +54,7 @@
|
||||
#define PRI_SWITCH_GR303_EOC 8 /* GR-303 Embedded Operations Channel */
|
||||
#define PRI_SWITCH_GR303_TMC 9 /* GR-303 Timeslot Management Channel */
|
||||
#define PRI_SWITCH_QSIG 10 /* QSIG Switch */
|
||||
/* Switchtypes 10 - 20 are reserved for internal use */
|
||||
/* Switchtypes 11 - 20 are reserved for internal use */
|
||||
|
||||
|
||||
/* PRI D-Channel Events */
|
||||
@ -322,6 +323,7 @@ typedef struct pri_event_hangup {
|
||||
int cause;
|
||||
int cref;
|
||||
q931_call *call; /* Opaque call pointer */
|
||||
long aoc_units; /* Advise of Charge number of charged units */
|
||||
} pri_event_hangup;
|
||||
|
||||
typedef struct pri_event_restart_ack {
|
||||
|
3
pri.c
3
pri.c
@ -474,6 +474,9 @@ int pri_channel_bridge(q931_call *call1, q931_call *call2)
|
||||
call2->pri->switchtype != PRI_SWITCH_LUCENT5E)
|
||||
return -1;
|
||||
|
||||
/* Check for bearer capability */
|
||||
if (call1->transcapability != call2->transcapability)
|
||||
return -1;
|
||||
/* Check to see if calls are on the same PRI dchannel
|
||||
* Currently only support calls on the same dchannel
|
||||
*/
|
||||
|
578
pri_facility.c
578
pri_facility.c
@ -16,6 +16,7 @@
|
||||
#include "pri_q931.h"
|
||||
#include "pri_facility.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -32,128 +33,151 @@ struct addressingdataelements_presentednumberunscreened {
|
||||
int pres;
|
||||
};
|
||||
|
||||
static void dump_apdu(unsigned char *c, int len)
|
||||
{
|
||||
#define MAX_APDU_LENGTH 255
|
||||
int i;
|
||||
char message[(2 + MAX_APDU_LENGTH * 3 + 6 + MAX_APDU_LENGTH + 3)] = ""; /* please adjust here, if you make changes below! */
|
||||
|
||||
if (len > MAX_APDU_LENGTH)
|
||||
return;
|
||||
|
||||
snprintf(message, sizeof(message)-1, " [");
|
||||
for (i=0; i<len; i++)
|
||||
snprintf((char *)(message+strlen(message)), sizeof(message)-strlen(message)-1, " %02x", c[i]);
|
||||
snprintf((char *)(message+strlen(message)), sizeof(message)-strlen(message)-1, " ] - [");
|
||||
for (i=0; i<len; i++) {
|
||||
if (c[i] < 20 || c[i] >= 128)
|
||||
snprintf((char *)(message+strlen(message)), sizeof(message)-strlen(message)-1, "°");
|
||||
else
|
||||
snprintf((char *)(message+strlen(message)), sizeof(message)-strlen(message)-1, "%c", c[i]);
|
||||
}
|
||||
snprintf((char *)(message+strlen(message)), sizeof(message)-strlen(message)-1, "]\n");
|
||||
pri_message(message);
|
||||
}
|
||||
|
||||
int redirectingreason_from_q931(struct pri *pri, int redirectingreason)
|
||||
{
|
||||
switch(pri->switchtype) {
|
||||
case PRI_SWITCH_QSIG:
|
||||
switch(redirectingreason) {
|
||||
case PRI_REDIR_UNKNOWN:
|
||||
return QSIG_DIVERT_REASON_UNKNOWN;
|
||||
case PRI_REDIR_FORWARD_ON_BUSY:
|
||||
return QSIG_DIVERT_REASON_CFB;
|
||||
case PRI_REDIR_FORWARD_ON_NO_REPLY:
|
||||
return QSIG_DIVERT_REASON_CFNR;
|
||||
case PRI_REDIR_UNCONDITIONAL:
|
||||
return QSIG_DIVERT_REASON_CFU;
|
||||
case PRI_REDIR_DEFLECTION:
|
||||
case PRI_REDIR_DTE_OUT_OF_ORDER:
|
||||
case PRI_REDIR_FORWARDED_BY_DTE:
|
||||
pri_message("!! Don't know how to convert Q.931 redirection reason %d to Q.SIG\n", redirectingreason);
|
||||
/* Fall through */
|
||||
case PRI_SWITCH_QSIG:
|
||||
switch(redirectingreason) {
|
||||
case PRI_REDIR_UNKNOWN:
|
||||
return QSIG_DIVERT_REASON_UNKNOWN;
|
||||
case PRI_REDIR_FORWARD_ON_BUSY:
|
||||
return QSIG_DIVERT_REASON_CFB;
|
||||
case PRI_REDIR_FORWARD_ON_NO_REPLY:
|
||||
return QSIG_DIVERT_REASON_CFNR;
|
||||
case PRI_REDIR_UNCONDITIONAL:
|
||||
return QSIG_DIVERT_REASON_CFU;
|
||||
case PRI_REDIR_DEFLECTION:
|
||||
case PRI_REDIR_DTE_OUT_OF_ORDER:
|
||||
case PRI_REDIR_FORWARDED_BY_DTE:
|
||||
pri_message("!! Don't know how to convert Q.931 redirection reason %d to Q.SIG\n", redirectingreason);
|
||||
/* Fall through */
|
||||
default:
|
||||
return QSIG_DIVERT_REASON_UNKNOWN;
|
||||
}
|
||||
default:
|
||||
return QSIG_DIVERT_REASON_UNKNOWN;
|
||||
}
|
||||
default:
|
||||
switch(redirectingreason) {
|
||||
case PRI_REDIR_UNKNOWN:
|
||||
return Q952_DIVERT_REASON_UNKNOWN;
|
||||
case PRI_REDIR_FORWARD_ON_BUSY:
|
||||
return Q952_DIVERT_REASON_CFB;
|
||||
case PRI_REDIR_FORWARD_ON_NO_REPLY:
|
||||
return Q952_DIVERT_REASON_CFNR;
|
||||
case PRI_REDIR_DEFLECTION:
|
||||
return Q952_DIVERT_REASON_CD;
|
||||
case PRI_REDIR_UNCONDITIONAL:
|
||||
return Q952_DIVERT_REASON_CFU;
|
||||
case PRI_REDIR_DTE_OUT_OF_ORDER:
|
||||
case PRI_REDIR_FORWARDED_BY_DTE:
|
||||
pri_message("!! Don't know how to convert Q.931 redirection reason %d to Q.952\n", redirectingreason);
|
||||
/* Fall through */
|
||||
default:
|
||||
return Q952_DIVERT_REASON_UNKNOWN;
|
||||
}
|
||||
switch(redirectingreason) {
|
||||
case PRI_REDIR_UNKNOWN:
|
||||
return Q952_DIVERT_REASON_UNKNOWN;
|
||||
case PRI_REDIR_FORWARD_ON_BUSY:
|
||||
return Q952_DIVERT_REASON_CFB;
|
||||
case PRI_REDIR_FORWARD_ON_NO_REPLY:
|
||||
return Q952_DIVERT_REASON_CFNR;
|
||||
case PRI_REDIR_DEFLECTION:
|
||||
return Q952_DIVERT_REASON_CD;
|
||||
case PRI_REDIR_UNCONDITIONAL:
|
||||
return Q952_DIVERT_REASON_CFU;
|
||||
case PRI_REDIR_DTE_OUT_OF_ORDER:
|
||||
case PRI_REDIR_FORWARDED_BY_DTE:
|
||||
pri_message("!! Don't know how to convert Q.931 redirection reason %d to Q.952\n", redirectingreason);
|
||||
/* Fall through */
|
||||
default:
|
||||
return Q952_DIVERT_REASON_UNKNOWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int redirectingreason_for_q931(struct pri *pri, int redirectingreason)
|
||||
{
|
||||
switch(pri->switchtype) {
|
||||
case PRI_SWITCH_QSIG:
|
||||
switch(redirectingreason) {
|
||||
case QSIG_DIVERT_REASON_UNKNOWN:
|
||||
return PRI_REDIR_UNKNOWN;
|
||||
case QSIG_DIVERT_REASON_CFU:
|
||||
return PRI_REDIR_UNCONDITIONAL;
|
||||
case QSIG_DIVERT_REASON_CFB:
|
||||
return PRI_REDIR_FORWARD_ON_BUSY;
|
||||
case QSIG_DIVERT_REASON_CFNR:
|
||||
return PRI_REDIR_FORWARD_ON_NO_REPLY;
|
||||
case PRI_SWITCH_QSIG:
|
||||
switch(redirectingreason) {
|
||||
case QSIG_DIVERT_REASON_UNKNOWN:
|
||||
return PRI_REDIR_UNKNOWN;
|
||||
case QSIG_DIVERT_REASON_CFU:
|
||||
return PRI_REDIR_UNCONDITIONAL;
|
||||
case QSIG_DIVERT_REASON_CFB:
|
||||
return PRI_REDIR_FORWARD_ON_BUSY;
|
||||
case QSIG_DIVERT_REASON_CFNR:
|
||||
return PRI_REDIR_FORWARD_ON_NO_REPLY;
|
||||
default:
|
||||
pri_message("!! Unknown Q.SIG diversion reason %d\n", redirectingreason);
|
||||
return PRI_REDIR_UNKNOWN;
|
||||
}
|
||||
default:
|
||||
pri_message("!! Unknown Q.SIG diversion reason %d\n", redirectingreason);
|
||||
return PRI_REDIR_UNKNOWN;
|
||||
}
|
||||
default:
|
||||
switch(redirectingreason) {
|
||||
case Q952_DIVERT_REASON_UNKNOWN:
|
||||
return PRI_REDIR_UNKNOWN;
|
||||
case Q952_DIVERT_REASON_CFU:
|
||||
return PRI_REDIR_UNCONDITIONAL;
|
||||
case Q952_DIVERT_REASON_CFB:
|
||||
return PRI_REDIR_FORWARD_ON_BUSY;
|
||||
case Q952_DIVERT_REASON_CFNR:
|
||||
return PRI_REDIR_FORWARD_ON_NO_REPLY;
|
||||
case Q952_DIVERT_REASON_CD:
|
||||
return PRI_REDIR_DEFLECTION;
|
||||
case Q952_DIVERT_REASON_IMMEDIATE:
|
||||
pri_message("!! Dont' know how to convert Q.952 diversion reason IMMEDIATE to PRI analog\n");
|
||||
return PRI_REDIR_UNKNOWN; /* ??? */
|
||||
default:
|
||||
pri_message("!! Unknown Q.952 diversion reason %d\n", redirectingreason);
|
||||
return PRI_REDIR_UNKNOWN;
|
||||
}
|
||||
switch(redirectingreason) {
|
||||
case Q952_DIVERT_REASON_UNKNOWN:
|
||||
return PRI_REDIR_UNKNOWN;
|
||||
case Q952_DIVERT_REASON_CFU:
|
||||
return PRI_REDIR_UNCONDITIONAL;
|
||||
case Q952_DIVERT_REASON_CFB:
|
||||
return PRI_REDIR_FORWARD_ON_BUSY;
|
||||
case Q952_DIVERT_REASON_CFNR:
|
||||
return PRI_REDIR_FORWARD_ON_NO_REPLY;
|
||||
case Q952_DIVERT_REASON_CD:
|
||||
return PRI_REDIR_DEFLECTION;
|
||||
case Q952_DIVERT_REASON_IMMEDIATE:
|
||||
pri_message("!! Dont' know how to convert Q.952 diversion reason IMMEDIATE to PRI analog\n");
|
||||
return PRI_REDIR_UNKNOWN; /* ??? */
|
||||
default:
|
||||
pri_message("!! Unknown Q.952 diversion reason %d\n", redirectingreason);
|
||||
return PRI_REDIR_UNKNOWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int typeofnumber_from_q931(struct pri *pri, int ton)
|
||||
{
|
||||
switch(ton) {
|
||||
case PRI_TON_INTERNATIONAL:
|
||||
return Q932_TON_INTERNATIONAL;
|
||||
case PRI_TON_NATIONAL:
|
||||
return Q932_TON_NATIONAL;
|
||||
case PRI_TON_NET_SPECIFIC:
|
||||
return Q932_TON_NET_SPECIFIC;
|
||||
case PRI_TON_SUBSCRIBER:
|
||||
return Q932_TON_SUBSCRIBER;
|
||||
case PRI_TON_ABBREVIATED:
|
||||
return Q932_TON_ABBREVIATED;
|
||||
case PRI_TON_RESERVED:
|
||||
default:
|
||||
pri_message("!! Unsupported Q.931 TypeOfNumber value (%d)\n", ton);
|
||||
/* fall through */
|
||||
case PRI_TON_UNKNOWN:
|
||||
return Q932_TON_UNKNOWN;
|
||||
case PRI_TON_INTERNATIONAL:
|
||||
return Q932_TON_INTERNATIONAL;
|
||||
case PRI_TON_NATIONAL:
|
||||
return Q932_TON_NATIONAL;
|
||||
case PRI_TON_NET_SPECIFIC:
|
||||
return Q932_TON_NET_SPECIFIC;
|
||||
case PRI_TON_SUBSCRIBER:
|
||||
return Q932_TON_SUBSCRIBER;
|
||||
case PRI_TON_ABBREVIATED:
|
||||
return Q932_TON_ABBREVIATED;
|
||||
case PRI_TON_RESERVED:
|
||||
default:
|
||||
pri_message("!! Unsupported Q.931 TypeOfNumber value (%d)\n", ton);
|
||||
/* fall through */
|
||||
case PRI_TON_UNKNOWN:
|
||||
return Q932_TON_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static int typeofnumber_for_q931(struct pri *pri, int ton)
|
||||
{
|
||||
switch (ton) {
|
||||
case Q932_TON_UNKNOWN:
|
||||
return PRI_TON_UNKNOWN;
|
||||
case Q932_TON_INTERNATIONAL:
|
||||
return PRI_TON_INTERNATIONAL;
|
||||
case Q932_TON_NATIONAL:
|
||||
return PRI_TON_NATIONAL;
|
||||
case Q932_TON_NET_SPECIFIC:
|
||||
return PRI_TON_NET_SPECIFIC;
|
||||
case Q932_TON_SUBSCRIBER:
|
||||
return PRI_TON_SUBSCRIBER;
|
||||
case Q932_TON_ABBREVIATED:
|
||||
return PRI_TON_ABBREVIATED;
|
||||
default:
|
||||
pri_message("!! Invalid Q.932 TypeOfNumber %d\n", ton);
|
||||
return PRI_TON_UNKNOWN;
|
||||
case Q932_TON_UNKNOWN:
|
||||
return PRI_TON_UNKNOWN;
|
||||
case Q932_TON_INTERNATIONAL:
|
||||
return PRI_TON_INTERNATIONAL;
|
||||
case Q932_TON_NATIONAL:
|
||||
return PRI_TON_NATIONAL;
|
||||
case Q932_TON_NET_SPECIFIC:
|
||||
return PRI_TON_NET_SPECIFIC;
|
||||
case Q932_TON_SUBSCRIBER:
|
||||
return PRI_TON_SUBSCRIBER;
|
||||
case Q932_TON_ABBREVIATED:
|
||||
return PRI_TON_ABBREVIATED;
|
||||
default:
|
||||
pri_message("!! Invalid Q.932 TypeOfNumber %d\n", ton);
|
||||
return PRI_TON_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
@ -235,39 +259,39 @@ static int rose_address_decode(struct pri *pri, q931_call *call, unsigned char *
|
||||
GET_COMPONENT(comp, i, vdata, len);
|
||||
|
||||
switch(comp->type) {
|
||||
case 0xA0: /* unknownPartyNumber */
|
||||
case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* [0] unknownPartyNumber */
|
||||
if(rose_number_digits_decode(pri, call, comp->data, comp->len, value))
|
||||
return -1;
|
||||
value->npi = PRI_NPI_UNKNOWN;
|
||||
value->ton = PRI_TON_UNKNOWN;
|
||||
break;
|
||||
case 0xA1: /* publicPartyNumber */
|
||||
case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1): /* [1] publicPartyNumber */
|
||||
if(rose_public_party_number_decode(pri, call, comp->data, comp->len, value) != 0)
|
||||
return -1;
|
||||
value->npi = PRI_NPI_E163_E164;
|
||||
break;
|
||||
case 0xA2: /* nsapEncodedNumber */
|
||||
case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_2): /* [2] nsapEncodedNumber */
|
||||
pri_message("!! NsapEncodedNumber isn't handled\n");
|
||||
return -1;
|
||||
case 0xA3: /* dataPartyNumber */
|
||||
case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] dataPartyNumber */
|
||||
if(rose_number_digits_decode(pri, call, comp->data, comp->len, value))
|
||||
return -1;
|
||||
value->npi = PRI_NPI_X121 /* ??? */;
|
||||
value->ton = PRI_TON_UNKNOWN /* ??? */;
|
||||
pri_message("!! dataPartyNumber isn't handled\n");
|
||||
return -1;
|
||||
case 0xA4: /* telexPartyNumber */
|
||||
case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_4): /* [4] telexPartyNumber */
|
||||
if (rose_number_digits_decode(pri, call, comp->data, comp->len, value))
|
||||
return -1;
|
||||
value->npi = PRI_NPI_F69 /* ??? */;
|
||||
value->ton = PRI_TON_UNKNOWN /* ??? */;
|
||||
pri_message("!! telexPartyNumber isn't handled\n");
|
||||
return -1;
|
||||
case 0xA5: /* priavePartyNumber */
|
||||
case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_5): /* [5] priavePartyNumber */
|
||||
pri_message("!! privatePartyNumber isn't handled\n");
|
||||
value->npi = PRI_NPI_PRIVATE;
|
||||
return -1;
|
||||
case 0xA8: /* nationalStandardPartyNumber */
|
||||
case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_8): /* [8] nationalStandardPartyNumber */
|
||||
if (rose_number_digits_decode(pri, call, comp->data, comp->len, value))
|
||||
return -1;
|
||||
value->npi = PRI_NPI_NATIONAL;
|
||||
@ -302,24 +326,24 @@ static int rose_presented_number_unscreened_decode(struct pri *pri, q931_call *c
|
||||
GET_COMPONENT(comp, i, vdata, len);
|
||||
|
||||
switch(comp->type) {
|
||||
case 0xA0: /* [0] presentationAllowedNumber */
|
||||
case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* [0] presentationAllowedNumber */
|
||||
value->pres = PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
|
||||
return rose_address_decode(pri, call, comp->data, comp->len, value);
|
||||
case 0x81: /* [1] IMPLICIT presentationRestricted */
|
||||
case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1): /* [1] IMPLICIT presentationRestricted */
|
||||
if (comp->len != 0) { /* must be NULL */
|
||||
pri_error("!! Invalid PresentationRestricted component received (len != 0)\n");
|
||||
return -1;
|
||||
}
|
||||
value->pres = PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
|
||||
return 0;
|
||||
case 0x82: /* [2] IMPLICIT numberNotAvailableDueToInterworking */
|
||||
case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2): /* [2] IMPLICIT numberNotAvailableDueToInterworking */
|
||||
if (comp->len != 0) { /* must be NULL */
|
||||
pri_error("!! Invalid NumberNotAvailableDueToInterworking component received (len != 0)\n");
|
||||
return -1;
|
||||
}
|
||||
value->pres = PRES_NUMBER_NOT_AVAILABLE;
|
||||
return 0;
|
||||
case 0xA3: /* [3] presentationRestrictedNumber */
|
||||
case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] presentationRestrictedNumber */
|
||||
value->pres = PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
|
||||
return rose_address_decode(pri, call, comp->data, comp->len, value);
|
||||
default:
|
||||
@ -419,7 +443,7 @@ static int rose_diverting_leg_information2_encode(struct pri *pri, q931_call *ca
|
||||
return -1;
|
||||
}
|
||||
|
||||
buffer[i] = 0x80 | Q932_PROTOCOL_EXTENSIONS;
|
||||
buffer[i] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
|
||||
i++;
|
||||
/* Interpretation component */
|
||||
ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0x00 /* Discard unrecognized invokes */);
|
||||
@ -436,7 +460,7 @@ static int rose_diverting_leg_information2_encode(struct pri *pri, q931_call *ca
|
||||
ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, ROSE_DIVERTING_LEG_INFORMATION2);
|
||||
|
||||
/* ROSE ARGUMENT component */
|
||||
ASN1_ADD_SIMPLE(comp, 0x30, buffer, i);
|
||||
ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
|
||||
ASN1_PUSH(compstk, compsp, comp);
|
||||
/* ROSE DivertingLegInformation2.diversionCounter component */
|
||||
/* Always is 1 because other isn't available in the current design */
|
||||
@ -446,7 +470,7 @@ static int rose_diverting_leg_information2_encode(struct pri *pri, q931_call *ca
|
||||
ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, redirectingreason_from_q931(pri, call->redirectingreason));
|
||||
|
||||
/* ROSE DivertingLegInformation2.divertingNr component */
|
||||
ASN1_ADD_SIMPLE(comp, 0xA1, buffer, i);
|
||||
ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i);
|
||||
|
||||
ASN1_PUSH(compstk, compsp, comp);
|
||||
/* Redirecting information always not screened */
|
||||
@ -455,10 +479,10 @@ static int rose_diverting_leg_information2_encode(struct pri *pri, q931_call *ca
|
||||
case PRES_ALLOWED_USER_NUMBER_NOT_SCREENED:
|
||||
case PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN:
|
||||
if (call->redirectingnum && strlen(call->redirectingnum)) {
|
||||
ASN1_ADD_SIMPLE(comp, 0xA0, buffer, i);
|
||||
ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0), buffer, i);
|
||||
ASN1_PUSH(compstk, compsp, comp);
|
||||
/* NPI of redirected number is not supported in the current design */
|
||||
ASN1_ADD_SIMPLE(comp, 0xA1, buffer, i);
|
||||
ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i);
|
||||
ASN1_PUSH(compstk, compsp, comp);
|
||||
ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, typeofnumber_from_q931(pri, call->redirectingplan >> 4));
|
||||
j = asn1_string_encode(ASN1_NUMERICSTRING, &buffer[i], len - i, 20, call->redirectingnum, strlen(call->redirectingnum));
|
||||
@ -473,35 +497,35 @@ static int rose_diverting_leg_information2_encode(struct pri *pri, q931_call *ca
|
||||
/* fall through */
|
||||
case PRES_PROHIB_USER_NUMBER_PASSED_SCREEN:
|
||||
case PRES_PROHIB_USER_NUMBER_NOT_SCREENED:
|
||||
ASN1_ADD_SIMPLE(comp, 0x81, buffer, i);
|
||||
ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), buffer, i);
|
||||
break;
|
||||
/* Don't know how to handle this */
|
||||
case PRES_ALLOWED_NETWORK_NUMBER:
|
||||
case PRES_PROHIB_NETWORK_NUMBER:
|
||||
case PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN:
|
||||
case PRES_PROHIB_USER_NUMBER_FAILED_SCREEN:
|
||||
ASN1_ADD_SIMPLE(comp, 0x81, buffer, i);
|
||||
ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), buffer, i);
|
||||
break;
|
||||
default:
|
||||
pri_message("!! Undefined presentation value for redirecting number: %d\n", call->redirectingpres);
|
||||
case PRES_NUMBER_NOT_AVAILABLE:
|
||||
ASN1_ADD_SIMPLE(comp, 0x82, buffer, i);
|
||||
ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i);
|
||||
break;
|
||||
}
|
||||
ASN1_FIXUP(compstk, compsp, buffer, i);
|
||||
|
||||
/* ROSE DivertingLegInformation2.originalCalledNr component */
|
||||
/* This information isn't supported by current design - duplicate divertingNr */
|
||||
ASN1_ADD_SIMPLE(comp, 0xA2, buffer, i);
|
||||
ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_2), buffer, i);
|
||||
ASN1_PUSH(compstk, compsp, comp);
|
||||
/* Redirecting information always not screened */
|
||||
switch(call->redirectingpres) {
|
||||
case PRES_ALLOWED_USER_NUMBER_NOT_SCREENED:
|
||||
case PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN:
|
||||
if (call->redirectingnum && strlen(call->redirectingnum)) {
|
||||
ASN1_ADD_SIMPLE(comp, 0xA0, buffer, i);
|
||||
ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0), buffer, i);
|
||||
ASN1_PUSH(compstk, compsp, comp);
|
||||
ASN1_ADD_SIMPLE(comp, 0xA1, buffer, i);
|
||||
ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i);
|
||||
ASN1_PUSH(compstk, compsp, comp);
|
||||
ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, typeofnumber_from_q931(pri, call->redirectingplan >> 4));
|
||||
|
||||
@ -517,19 +541,19 @@ static int rose_diverting_leg_information2_encode(struct pri *pri, q931_call *ca
|
||||
/* fall through */
|
||||
case PRES_PROHIB_USER_NUMBER_PASSED_SCREEN:
|
||||
case PRES_PROHIB_USER_NUMBER_NOT_SCREENED:
|
||||
ASN1_ADD_SIMPLE(comp, 0x81, buffer, i);
|
||||
ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), buffer, i);
|
||||
break;
|
||||
/* Don't know how to handle this */
|
||||
case PRES_ALLOWED_NETWORK_NUMBER:
|
||||
case PRES_PROHIB_NETWORK_NUMBER:
|
||||
case PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN:
|
||||
case PRES_PROHIB_USER_NUMBER_FAILED_SCREEN:
|
||||
ASN1_ADD_SIMPLE(comp, 0x81, buffer, i);
|
||||
ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), buffer, i);
|
||||
break;
|
||||
default:
|
||||
pri_message("!! Undefined presentation value for redirecting number: %d\n", call->redirectingpres);
|
||||
case PRES_NUMBER_NOT_AVAILABLE:
|
||||
ASN1_ADD_SIMPLE(comp, 0x82, buffer, i);
|
||||
ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i);
|
||||
break;
|
||||
}
|
||||
ASN1_FIXUP(compstk, compsp, buffer, i);
|
||||
@ -568,13 +592,13 @@ static int add_callername_facility_ies(struct pri *pri, q931_call *c)
|
||||
return -1;
|
||||
}
|
||||
|
||||
buffer[i++] = 0x80 | Q932_PROTOCOL_EXTENSIONS;
|
||||
buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
|
||||
/* Interpretation component */
|
||||
|
||||
ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i);
|
||||
ASN1_PUSH(compstk, compsp, comp);
|
||||
ASN1_ADD_BYTECOMP(comp, 0x80, buffer, i, 0);
|
||||
ASN1_ADD_BYTECOMP(comp, 0x82, buffer, i, 0);
|
||||
ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0);
|
||||
ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0);
|
||||
ASN1_FIXUP(compstk, compsp, buffer, i);
|
||||
|
||||
ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0);
|
||||
@ -607,13 +631,13 @@ static int add_callername_facility_ies(struct pri *pri, q931_call *c)
|
||||
namelen = 50; /* truncate the name */
|
||||
}
|
||||
|
||||
buffer[i++] = 0x80 | Q932_PROTOCOL_EXTENSIONS;
|
||||
buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
|
||||
/* Interpretation component */
|
||||
|
||||
ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i);
|
||||
ASN1_PUSH(compstk, compsp, comp);
|
||||
ASN1_ADD_BYTECOMP(comp, 0x80, buffer, i, 0);
|
||||
ASN1_ADD_BYTECOMP(comp, 0x82, buffer, i, 0);
|
||||
ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0);
|
||||
ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0);
|
||||
ASN1_FIXUP(compstk, compsp, buffer, i);
|
||||
|
||||
ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0);
|
||||
@ -627,7 +651,7 @@ static int add_callername_facility_ies(struct pri *pri, q931_call *c)
|
||||
/* Operation ID: Calling name */
|
||||
ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, SS_CNID_CALLINGNAME);
|
||||
|
||||
res = asn1_string_encode(0x80, &buffer[i], sizeof(buffer)-i, 50, c->callername, namelen);
|
||||
res = asn1_string_encode((ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), &buffer[i], sizeof(buffer)-i, 50, c->callername, namelen);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
i += res;
|
||||
@ -638,7 +662,6 @@ static int add_callername_facility_ies(struct pri *pri, q931_call *c)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* End Callername */
|
||||
|
||||
/* MWI related encode and decode functions */
|
||||
@ -661,13 +684,13 @@ extern int mwi_message_send(struct pri* pri, q931_call *call, struct pri_sr *req
|
||||
} else if (destlen > 20)
|
||||
destlen = 20; /* Destination number cannot be greater then 20 digits */
|
||||
|
||||
buffer[i++] = 0x80 | Q932_PROTOCOL_EXTENSIONS;
|
||||
buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
|
||||
/* Interpretation component */
|
||||
|
||||
ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i);
|
||||
ASN1_PUSH(compstk, compsp, comp);
|
||||
ASN1_ADD_BYTECOMP(comp, 0x80, buffer, i, 0);
|
||||
ASN1_ADD_BYTECOMP(comp, 0x82, buffer, i, 0);
|
||||
ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0);
|
||||
ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0);
|
||||
ASN1_FIXUP(compstk, compsp, buffer, i);
|
||||
|
||||
ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0);
|
||||
@ -678,10 +701,10 @@ extern int mwi_message_send(struct pri* pri, q931_call *call, struct pri_sr *req
|
||||
ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri));
|
||||
|
||||
ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, (activate) ? SS_MWI_ACTIVATE : SS_MWI_DEACTIVATE);
|
||||
ASN1_ADD_SIMPLE(comp, 0x30 /* Sequence */, buffer, i);
|
||||
ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
|
||||
ASN1_PUSH(compstk, compsp, comp);
|
||||
/* PartyNumber */
|
||||
res = asn1_string_encode(0x80, &buffer[i], sizeof(buffer)-i, destlen, req->called, destlen);
|
||||
res = asn1_string_encode((ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), &buffer[i], sizeof(buffer)-i, destlen, req->called, destlen);
|
||||
|
||||
if (res < 0)
|
||||
return -1;
|
||||
@ -718,13 +741,13 @@ extern int eect_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2)
|
||||
0x08,
|
||||
};
|
||||
|
||||
buffer[i++] = 0x80 | Q932_PROTOCOL_EXTENSIONS;
|
||||
buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
|
||||
/* Interpretation component */
|
||||
|
||||
ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i);
|
||||
ASN1_PUSH(compstk, compsp, comp);
|
||||
ASN1_ADD_BYTECOMP(comp, 0x80, buffer, i, 0);
|
||||
ASN1_ADD_BYTECOMP(comp, 0x82, buffer, i, 0);
|
||||
ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0);
|
||||
ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0);
|
||||
ASN1_FIXUP(compstk, compsp, buffer, i);
|
||||
|
||||
ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0);
|
||||
@ -739,9 +762,9 @@ extern int eect_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2)
|
||||
return -1;
|
||||
i += res;
|
||||
|
||||
ASN1_ADD_SIMPLE(comp, ASN1_SEQUENCE | 0x20, buffer, i);
|
||||
ASN1_ADD_SIMPLE(comp, (ASN1_SEQUENCE | ASN1_CONSTRUCTOR), buffer, i);
|
||||
ASN1_PUSH(compstk, compsp, comp);
|
||||
ASN1_ADD_WORDCOMP(comp, 0x02, buffer, i, call_reference);
|
||||
ASN1_ADD_WORDCOMP(comp, ASN1_INTEGER, buffer, i, call_reference);
|
||||
ASN1_FIXUP(compstk, compsp, buffer, i);
|
||||
ASN1_FIXUP(compstk, compsp, buffer, i);
|
||||
|
||||
@ -764,6 +787,211 @@ extern int eect_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2)
|
||||
}
|
||||
/* End EECT */
|
||||
|
||||
/* AOC */
|
||||
static int aoc_aoce_charging_request_decode(struct pri *pri, q931_call *call, unsigned char *data, int len)
|
||||
{
|
||||
int chargingcase = -1;
|
||||
unsigned char *vdata = data;
|
||||
struct rose_component *comp = NULL;
|
||||
int pos1 = 0;
|
||||
|
||||
if (pri->debug & PRI_DEBUG_AOC)
|
||||
dump_apdu (data, len);
|
||||
|
||||
do {
|
||||
GET_COMPONENT(comp, pos1, vdata, len);
|
||||
CHECK_COMPONENT(comp, ASN1_ENUMERATED, "!! Invalid AOC Charging Request argument. Expected Enumerated (0x0A) but Received 0x%02X\n");
|
||||
ASN1_GET_INTEGER(comp, chargingcase);
|
||||
if (chargingcase >= 0 && chargingcase <= 2) {
|
||||
if (pri->debug & PRI_DEBUG_APDU)
|
||||
pri_message("Channel %d/%d, Call %d - received AOC charging request - charging case: %i\n",
|
||||
call->ds1no, call->channelno, call->cr, chargingcase);
|
||||
} else {
|
||||
pri_message("!! unkown AOC ChargingCase: 0x%02X", chargingcase);
|
||||
chargingcase = -1;
|
||||
}
|
||||
NEXT_COMPONENT(comp, pos1);
|
||||
} while (pos1 < len);
|
||||
if (pos1 < len) {
|
||||
pri_message("!! Only reached position %i in %i bytes long AOC-E structure:", pos1, len );
|
||||
dump_apdu (data, len);
|
||||
return -1; /* Aborted before */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int aoc_aoce_charging_unit_decode(struct pri *pri, q931_call *call, unsigned char *data, int len)
|
||||
{
|
||||
long chargingunits = 0, chargetype = -1, temp, chargeIdentifier = -1;
|
||||
unsigned char *vdata = data;
|
||||
struct rose_component *comp1 = NULL, *comp2 = NULL, *comp3 = NULL;
|
||||
int pos1 = 0, pos2, pos3, sublen2, sublen3;
|
||||
struct addressingdataelements_presentednumberunscreened chargednr;
|
||||
|
||||
if (pri->debug & PRI_DEBUG_AOC)
|
||||
dump_apdu (data, len);
|
||||
|
||||
do {
|
||||
GET_COMPONENT(comp1, pos1, vdata, len); /* AOCEChargingUnitInfo */
|
||||
CHECK_COMPONENT(comp1, ASN1_SEQUENCE, "!! Invalid AOC-E Charging Unit argument. Expected Sequence (0x30) but Received 0x%02X\n");
|
||||
SUB_COMPONENT(comp1, pos1);
|
||||
GET_COMPONENT(comp1, pos1, vdata, len);
|
||||
switch (comp1->type) {
|
||||
case (ASN1_SEQUENCE | ASN1_CONSTRUCTOR): /* specificChargingUnits */
|
||||
sublen2 = comp1->len;
|
||||
pos2 = pos1;
|
||||
comp2 = comp1;
|
||||
SUB_COMPONENT(comp2, pos2);
|
||||
do {
|
||||
GET_COMPONENT(comp2, pos2, vdata, len);
|
||||
switch (comp2->type) {
|
||||
case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1): /* RecordedUnitsList (0xA1) */
|
||||
SUB_COMPONENT(comp2, pos2);
|
||||
GET_COMPONENT(comp2, pos2, vdata, len);
|
||||
CHECK_COMPONENT(comp2, ASN1_SEQUENCE, "!! Invalid AOC-E Charging Unit argument. Expected Sequence (0x30) but received 0x02%X\n"); /* RecordedUnits */
|
||||
sublen3 = pos2 + comp2->len;
|
||||
pos3 = pos2;
|
||||
comp3 = comp2;
|
||||
SUB_COMPONENT(comp3, pos3);
|
||||
do {
|
||||
GET_COMPONENT(comp3, pos3, vdata, len);
|
||||
switch (comp3->type) {
|
||||
case ASN1_INTEGER: /* numberOfUnits */
|
||||
ASN1_GET_INTEGER(comp3, temp);
|
||||
chargingunits += temp;
|
||||
case ASN1_NULL: /* notAvailable */
|
||||
break;
|
||||
default:
|
||||
pri_message("!! Don't know how to handle 0x%02X in AOC-E RecordedUnits\n", comp3->type);
|
||||
}
|
||||
NEXT_COMPONENT(comp3, pos3);
|
||||
} while (pos3 < sublen3);
|
||||
if (pri->debug & PRI_DEBUG_AOC)
|
||||
pri_message("Channel %d/%d, Call %d - received AOC-E charging: %i unit%s\n",
|
||||
call->ds1no, call->channelno, call->cr, chargingunits, (chargingunits == 1) ? "" : "s");
|
||||
break;
|
||||
case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_2): /* AOCEBillingID (0xA2) */
|
||||
SUB_COMPONENT(comp2, pos2);
|
||||
GET_COMPONENT(comp2, pos2, vdata, len);
|
||||
ASN1_GET_INTEGER(comp2, chargetype);
|
||||
pri_message("!! not handled: Channel %d/%d, Call %d - received AOC-E billing ID: %i\n",
|
||||
call->ds1no, call->channelno, call->cr, chargetype);
|
||||
break;
|
||||
default:
|
||||
pri_message("!! Don't know how to handle 0x%02X in AOC-E RecordedUnitsList\n", comp2->type);
|
||||
}
|
||||
NEXT_COMPONENT(comp2, pos2);
|
||||
} while (pos2 < sublen2);
|
||||
break;
|
||||
case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1): /* freeOfCharge (0x81) */
|
||||
if (pri->debug & PRI_DEBUG_AOC)
|
||||
pri_message("Channel %d/%d, Call %d - received AOC-E free of charge\n", call->ds1no, call->channelno, call->cr);
|
||||
chargingunits = 0;
|
||||
break;
|
||||
default:
|
||||
pri_message("!! Invalid AOC-E specificChargingUnits. Expected Sequence (0x30) or Object Identifier (0x81/0x01) but received 0x%02X\n", comp1->type);
|
||||
}
|
||||
NEXT_COMPONENT(comp1, pos1);
|
||||
GET_COMPONENT(comp1, pos1, vdata, len); /* get optional chargingAssociation. will 'break' when reached end of structure */
|
||||
switch (comp1->type) {
|
||||
/* TODO: charged number is untested - please report! */
|
||||
case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* chargedNumber (0xA0) */
|
||||
if(rose_presented_number_unscreened_decode(pri, call, comp1->data, comp1->len, &chargednr) != 0)
|
||||
return -1;
|
||||
pri_message("!! not handled: Received ChargedNr '%s' \n", chargednr.partyaddress);
|
||||
pri_message(" ton = %d, pres = %d, npi = %d\n", chargednr.ton, chargednr.pres, chargednr.npi);
|
||||
break;
|
||||
case ASN1_INTEGER:
|
||||
ASN1_GET_INTEGER(comp1, chargeIdentifier);
|
||||
break;
|
||||
default:
|
||||
pri_message("!! Invalid AOC-E chargingAssociation. Expected Object Identifier (0xA0) or Integer (0x02) but received 0x%02X\n", comp1->type);
|
||||
}
|
||||
NEXT_COMPONENT(comp1, pos1);
|
||||
} while (pos1 < len);
|
||||
|
||||
if (pos1 < len) {
|
||||
pri_message("!! Only reached position %i in %i bytes long AOC-E structure:", pos1, len );
|
||||
dump_apdu (data, len);
|
||||
return -1; /* oops - aborted before */
|
||||
}
|
||||
call->aoc_units = chargingunits;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aoc_aoce_charging_unit_encode(struct pri *pri, q931_call *c, long chargedunits)
|
||||
{
|
||||
/* sample data: [ 91 a1 12 02 02 3a 78 02 01 24 30 09 30 07 a1 05 30 03 02 01 01 ] */
|
||||
int i = 0, res = 0, compsp = 0;
|
||||
unsigned char buffer[255] = "";
|
||||
struct rose_component *comp = NULL, *compstk[10];
|
||||
|
||||
/* ROSE protocol (0x91)*/
|
||||
buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_ROSE);
|
||||
|
||||
/* ROSE Component (0xA1,len)*/
|
||||
ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
|
||||
ASN1_PUSH(compstk, compsp, comp);
|
||||
|
||||
/* ROSE invokeId component (0x02,len,id)*/
|
||||
ASN1_ADD_WORDCOMP(comp, INVOKE_IDENTIFIER, buffer, i, ++pri->last_invoke);
|
||||
|
||||
/* ROSE operationId component (0x02,0x01,0x24)*/
|
||||
ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, ROSE_AOC_AOCE_CHARGING_UNIT);
|
||||
|
||||
/* AOCEChargingUnitInfo (0x30,len) */
|
||||
ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
|
||||
ASN1_PUSH(compstk, compsp, comp);
|
||||
|
||||
if (chargedunits > 0) {
|
||||
/* SpecificChargingUnits (0x30,len) */
|
||||
ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
|
||||
ASN1_PUSH(compstk, compsp, comp);
|
||||
|
||||
/* RecordedUnitsList (0xA1,len) */
|
||||
ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i);
|
||||
ASN1_PUSH(compstk, compsp, comp);
|
||||
|
||||
/* RecordedUnits (0x30,len) */
|
||||
ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
|
||||
ASN1_PUSH(compstk, compsp, comp);
|
||||
|
||||
/* NumberOfUnits (0x02,len,charge) */
|
||||
ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, chargedunits);
|
||||
|
||||
ASN1_FIXUP(compstk, compsp, buffer, i);
|
||||
ASN1_FIXUP(compstk, compsp, buffer, i);
|
||||
ASN1_FIXUP(compstk, compsp, buffer, i);
|
||||
} else {
|
||||
/* freeOfCharge (0x81,0) */
|
||||
ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), buffer, i);
|
||||
}
|
||||
ASN1_FIXUP(compstk, compsp, buffer, i);
|
||||
ASN1_FIXUP(compstk, compsp, buffer, i);
|
||||
|
||||
if (pri->debug & PRI_DEBUG_AOC)
|
||||
dump_apdu (buffer, i);
|
||||
|
||||
/* code below is untested */
|
||||
res = pri_call_apdu_queue(c, Q931_FACILITY, buffer, i, NULL, NULL);
|
||||
if (res) {
|
||||
pri_message("Could not queue ADPU in facility message\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Remember that if we queue a facility IE for a facility message we
|
||||
* have to explicitly send the facility message ourselves */
|
||||
res = q931_facility(c->pri, c);
|
||||
if (res) {
|
||||
pri_message("Could not schedule facility message for call %d\n", c->cr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* End AOC */
|
||||
|
||||
extern int rose_invoke_decode(struct pri *pri, q931_call *call, unsigned char *data, int len)
|
||||
{
|
||||
@ -775,7 +1003,7 @@ extern int rose_invoke_decode(struct pri *pri, q931_call *call, unsigned char *d
|
||||
do {
|
||||
/* Invoke ID stuff */
|
||||
GET_COMPONENT(comp, i, vdata, len);
|
||||
CHECK_COMPONENT(comp, ASN1_INTEGER, "Don't know what to do if first ROSE component is of type 0x%x\n");
|
||||
CHECK_COMPONENT(comp, INVOKE_IDENTIFIER, "Don't know what to do if first ROSE component is of type 0x%x\n");
|
||||
invokeid = comp;
|
||||
NEXT_COMPONENT(comp, i);
|
||||
|
||||
@ -806,23 +1034,77 @@ extern int rose_invoke_decode(struct pri *pri, q931_call *call, unsigned char *d
|
||||
memcpy(call->callername, comp->data, comp->len);
|
||||
call->callername[comp->len] = 0;
|
||||
if (pri->debug & PRI_DEBUG_APDU)
|
||||
pri_message(" Received caller name '%s'\n", call->callername);
|
||||
pri_message(" Received caller name '%s'\n", call->callername);
|
||||
return 0;
|
||||
default:
|
||||
pri_message("Do not handle argument of type 0x%X\n", comp->type);
|
||||
if (pri->debug & PRI_DEBUG_APDU)
|
||||
pri_message("Do not handle argument of type 0x%X\n", comp->type);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case ROSE_DIVERTING_LEG_INFORMATION2:
|
||||
if (pri->debug & PRI_DEBUG_APDU)
|
||||
pri_message(" Handle DivertingLegInformation2\n");
|
||||
if (comp->type != 0x30) { /* Sequence */
|
||||
if (comp->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */
|
||||
pri_message("Invalid DivertingLegInformation2Type argument\n");
|
||||
return -1;
|
||||
}
|
||||
return rose_diverting_leg_information2_decode(pri, call, comp->data, comp->len);
|
||||
case ROSE_AOC_NO_CHARGING_INFO_AVAILABLE:
|
||||
if (pri->debug & PRI_DEBUG_APDU) {
|
||||
pri_message("ROSE %i: AOC No Charging Info Available - not handled!", operation_tag);
|
||||
dump_apdu (comp->data, comp->len);
|
||||
}
|
||||
return -1;
|
||||
case ROSE_AOC_CHARGING_REQUEST:
|
||||
return aoc_aoce_charging_request_decode(pri, call, (u_int8_t *)comp, comp->len + 2);
|
||||
case ROSE_AOC_AOCS_CURRENCY:
|
||||
if (pri->debug & PRI_DEBUG_APDU) {
|
||||
pri_message("ROSE %i: AOC-S Currency - not handled!", operation_tag);
|
||||
dump_apdu ((u_int8_t *)comp, comp->len + 2);
|
||||
}
|
||||
return -1;
|
||||
case ROSE_AOC_AOCS_SPECIAL_ARR:
|
||||
if (pri->debug & PRI_DEBUG_APDU) {
|
||||
pri_message("ROSE %i: AOC-S Special Array - not handled!", operation_tag);
|
||||
dump_apdu ((u_int8_t *)comp, comp->len + 2);
|
||||
}
|
||||
return -1;
|
||||
case ROSE_AOC_AOCD_CURRENCY:
|
||||
if (pri->debug & PRI_DEBUG_APDU) {
|
||||
pri_message("ROSE %i: AOC-D Currency - not handled!", operation_tag);
|
||||
dump_apdu ((u_int8_t *)comp, comp->len + 2);
|
||||
}
|
||||
return -1;
|
||||
case ROSE_AOC_AOCD_CHARGING_UNIT:
|
||||
if (pri->debug & PRI_DEBUG_APDU) {
|
||||
pri_message("ROSE %i: AOC-D Charging Unit - not handled!", operation_tag);
|
||||
dump_apdu ((u_int8_t *)comp, comp->len + 2);
|
||||
}
|
||||
return -1;
|
||||
case ROSE_AOC_AOCE_CURRENCY:
|
||||
if (pri->debug & PRI_DEBUG_APDU) {
|
||||
pri_message("ROSE %i: AOC-E Currency - not handled!", operation_tag);
|
||||
dump_apdu ((u_int8_t *)comp, comp->len + 2);
|
||||
}
|
||||
return -1;
|
||||
case ROSE_AOC_AOCE_CHARGING_UNIT:
|
||||
return aoc_aoce_charging_unit_decode(pri, call, (u_int8_t *)comp, comp->len + 2);
|
||||
if (0) { /* the following function is currently not used - just to make the compiler happy */
|
||||
aoc_aoce_charging_unit_encode(pri, call, call->aoc_units); /* use this function to forward the aoc-e on a bridged channel */
|
||||
return 0;
|
||||
}
|
||||
case ROSE_AOC_IDENTIFICATION_OF_CHARGE:
|
||||
if (pri->debug & PRI_DEBUG_APDU) {
|
||||
pri_message("ROSE %i: AOC Identification Of Charge - not handled!", operation_tag);
|
||||
dump_apdu ((u_int8_t *)comp, comp->len + 2);
|
||||
}
|
||||
return -1;
|
||||
default:
|
||||
pri_message("!! Unable to handle ROSE operation %d\n", operation_tag);
|
||||
if (pri->debug & PRI_DEBUG_APDU) {
|
||||
pri_message("!! Unable to handle ROSE operation %d", operation_tag);
|
||||
dump_apdu ((u_int8_t *)comp, comp->len + 2);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
} while(0);
|
||||
@ -848,7 +1130,7 @@ extern int pri_call_apdu_queue(q931_call *call, int messagetype, void *apdu, int
|
||||
memcpy(new_event->apdu, apdu, apdu_len);
|
||||
new_event->apdu_len = apdu_len;
|
||||
} else {
|
||||
pri_error("malloc failed\n");
|
||||
pri_error("!! Malloc failed!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -32,10 +32,20 @@
|
||||
#define COMP_TYPE_NFE 0xAA
|
||||
|
||||
/* Operation ID values */
|
||||
/* Q.952 ROSE operations */
|
||||
/* Q.952 ROSE operations (Diverting) */
|
||||
#define ROSE_DIVERTING_LEG_INFORMATION1 18
|
||||
#define ROSE_DIVERTING_LEG_INFORMATION2 15
|
||||
#define ROSE_DIVERTING_LEG_INFORMATION3 19
|
||||
/* Q.956 ROSE operations (Advice Of Charge) */
|
||||
#define ROSE_AOC_NO_CHARGING_INFO_AVAILABLE 26
|
||||
#define ROSE_AOC_CHARGING_REQUEST 30
|
||||
#define ROSE_AOC_AOCS_CURRENCY 31
|
||||
#define ROSE_AOC_AOCS_SPECIAL_ARR 32
|
||||
#define ROSE_AOC_AOCD_CURRENCY 33
|
||||
#define ROSE_AOC_AOCD_CHARGING_UNIT 34
|
||||
#define ROSE_AOC_AOCE_CURRENCY 35
|
||||
#define ROSE_AOC_AOCE_CHARGING_UNIT 36
|
||||
#define ROSE_AOC_IDENTIFICATION_OF_CHARGE 37
|
||||
/* Q.SIG operations */
|
||||
#define SS_CNID_CALLINGNAME 0
|
||||
#define SS_DIVERTING_LEG_INFORMATION2 22
|
||||
@ -48,14 +58,15 @@
|
||||
#define INVOKE_LINKED_IDENTIFIER 0x80
|
||||
#define INVOKE_NULL_IDENTIFIER __USE_ASN1_NULL
|
||||
|
||||
/* ASN.1 Data types */
|
||||
/* ASN.1 Identifier Octet - Data types */
|
||||
#define ASN1_TYPE_MASK 0x1f
|
||||
#define ASN1_BOOLEAN 0x01
|
||||
#define ASN1_INTEGER 0x02
|
||||
#define ASN1_BITSTRING 0x03
|
||||
#define ASN1_OCTETSTRING 0x04
|
||||
#define ASN1_NULL 0x05
|
||||
#define ASN1_OBJECTIDENTIFIER 0x06
|
||||
#define ASN1_OBJECTDESCRIPTER 0x07
|
||||
#define ASN1_OBJECTDESCRIPTOR 0x07
|
||||
#define ASN1_EXTERN 0x08
|
||||
#define ASN1_REAL 0x09
|
||||
#define ASN1_ENUMERATED 0x0a
|
||||
@ -72,6 +83,31 @@
|
||||
#define ASN1_UTCTIME 0x17
|
||||
#define ASN1_GENERALIZEDTIME 0x18
|
||||
|
||||
/* ASN.1 Identifier Octet - Tags */
|
||||
#define ASN1_TAG_0 0x00
|
||||
#define ASN1_TAG_1 0x01
|
||||
#define ASN1_TAG_2 0x02
|
||||
#define ASN1_TAG_3 0x03
|
||||
#define ASN1_TAG_4 0x04
|
||||
#define ASN1_TAG_5 0x05
|
||||
#define ASN1_TAG_6 0x06
|
||||
#define ASN1_TAG_7 0x07
|
||||
#define ASN1_TAG_8 0x08
|
||||
#define ASN1_TAG_9 0x09
|
||||
|
||||
/* ASN.1 Identifier Octet - Primitive/Constructor Bit */
|
||||
#define ASN1_PC_MASK 0x20
|
||||
#define ASN1_PRIMITIVE 0x00
|
||||
#define ASN1_CONSTRUCTOR 0x20
|
||||
|
||||
/* ASN.1 Identifier Octet - Clan Bits */
|
||||
#define ASN1_CLAN_MASK 0xc0
|
||||
#define ASN1_UNIVERSAL 0x00
|
||||
#define ASN1_APPLICATION 0x40
|
||||
#define ASN1_CONTEXT_SPECIFIC 0x80
|
||||
#define ASN1_PRIVATE 0xc0
|
||||
|
||||
|
||||
#define INVOKE_OPERATION_INT __USE_ASN1_INTEGER
|
||||
#define INVOKE_OBJECT_ID __USE_ASN1_OBJECTIDENTIFIER
|
||||
|
||||
@ -103,7 +139,7 @@ struct rose_component {
|
||||
};
|
||||
|
||||
#define GET_COMPONENT(component, idx, ptr, length) \
|
||||
if ((idx)+2 >= (length)) \
|
||||
if ((idx)+2 > (length)) \
|
||||
break; \
|
||||
(component) = (struct rose_component*)&((ptr)[idx]); \
|
||||
if ((idx)+(component)->len+2 > (length)) { \
|
||||
@ -128,7 +164,7 @@ struct rose_component {
|
||||
(idx) += 2
|
||||
|
||||
#define CHECK_COMPONENT(component, comptype, message) \
|
||||
if ((component)->type && ((component)->type&0x1f) != (comptype)) { \
|
||||
if ((component)->type && ((component)->type & ASN1_TYPE_MASK) != (comptype)) { \
|
||||
pri_message((message), (component)->type); \
|
||||
break; \
|
||||
}
|
||||
|
@ -220,6 +220,8 @@ struct q931_call {
|
||||
char useruserinfo[256];
|
||||
char callingsubaddr[256]; /* Calling parties sub address */
|
||||
|
||||
long aoc_units; /* Advice of Charge Units */
|
||||
|
||||
struct apdu_event *apdus; /* APDU queue for call */
|
||||
};
|
||||
|
||||
|
4
q931.c
4
q931.c
@ -3170,6 +3170,7 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
||||
c->cause = -1;
|
||||
c->causecode = -1;
|
||||
c->causeloc = -1;
|
||||
c->aoc_units = -1;
|
||||
if (c->retranstimer)
|
||||
pri_schedule_del(pri, c->retranstimer);
|
||||
c->retranstimer = 0;
|
||||
@ -3183,6 +3184,7 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
||||
c->causecode = -1;
|
||||
c->causeloc = -1;
|
||||
c->sugcallstate = -1;
|
||||
c->aoc_units = -1;
|
||||
break;
|
||||
case Q931_RESTART_ACKNOWLEDGE:
|
||||
c->channelno = -1;
|
||||
@ -3538,6 +3540,7 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
||||
pri->ev.hangup.cref = c->cr;
|
||||
pri->ev.hangup.cause = c->cause;
|
||||
pri->ev.hangup.call = c;
|
||||
pri->ev.hangup.aoc_units = c->aoc_units;
|
||||
/* Don't send release complete if they send us release
|
||||
while we sent it, assume a NULL state */
|
||||
if (c->newcall)
|
||||
@ -3563,6 +3566,7 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
||||
pri->ev.hangup.cref = c->cr;
|
||||
pri->ev.hangup.cause = c->cause;
|
||||
pri->ev.hangup.call = c;
|
||||
pri->ev.hangup.aoc_units = c->aoc_units;
|
||||
if (c->alive)
|
||||
return Q931_RES_HAVEEVENT;
|
||||
else
|
||||
|
Loading…
Reference in New Issue
Block a user