Support for DivertingLegInformation2 ROSE ADPU. Thanks PCadach!
git-svn-id: https://origsvn.digium.com/svn/libpri/trunk@187 2fbb986a-6c06-0410-b554-c9c1f0a7f128
This commit is contained in:
469
pri_facility.c
469
pri_facility.c
@@ -16,56 +16,467 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int rose_invoke_decode(q931_call *call, unsigned char *data, int len)
|
||||
#undef DEBUG
|
||||
|
||||
struct addressingdataelements_presentednumberunscreened {
|
||||
char partyAddress[21];
|
||||
char partySubaddress[21];
|
||||
int npi;
|
||||
int ton;
|
||||
int pres;
|
||||
};
|
||||
|
||||
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 */
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int redirectingreason_for_q931(struct pri *pri, int redirectingreason)
|
||||
{
|
||||
switch(pri->switchtype) {
|
||||
case PRI_SWITCH_QSIG:
|
||||
switch(redirectingreason) {
|
||||
case QSIG_DIVERT_REASON_UNKNOWN:
|
||||
return PRI_REDIR_UNKNOWN;
|
||||
case QSIG_DIVERT_REASON_CFU:
|
||||
return PRI_REDIR_UNCONDITIONAL;
|
||||
case QSIG_DIVERT_REASON_CFB:
|
||||
return PRI_REDIR_FORWARD_ON_BUSY;
|
||||
case QSIG_DIVERT_REASON_CFNR:
|
||||
return PRI_REDIR_FORWARD_ON_NO_REPLY;
|
||||
default:
|
||||
pri_message("!! 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
int asn1_string_encode(unsigned char asn1_type, void *data, int len, int max_len, void *src, int src_len)
|
||||
{
|
||||
struct rose_component *comp = NULL;
|
||||
|
||||
if (len < 2 + src_len)
|
||||
return -1;
|
||||
|
||||
if (max_len && (src_len > max_len))
|
||||
src_len = max_len;
|
||||
|
||||
comp = (struct rose_component *)data;
|
||||
comp->type = asn1_type;
|
||||
comp->len = src_len;
|
||||
memcpy(comp->data, src, src_len);
|
||||
|
||||
return 2 + src_len;
|
||||
}
|
||||
|
||||
static int rose_number_digits_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
|
||||
{
|
||||
int i = 0;
|
||||
unsigned char *vdata = data;
|
||||
struct rose_component *comp = NULL;
|
||||
unsigned char *vdata = data;
|
||||
|
||||
if (len <= 0) return -1;
|
||||
do {
|
||||
GET_COMPONENT(comp, i, vdata, len);
|
||||
CHECK_COMPONENT(comp, ASN1_NUMERICSTRING, "Don't know what to do with PublicPartyNumber ROSE component type 0x%x\n");
|
||||
if(comp->len > 20) {
|
||||
pri_message("!! Oversized NumberDigits component (%d)\n", comp->len);
|
||||
return -1;
|
||||
}
|
||||
memcpy(value->partyAddress, comp->data, comp->len);
|
||||
value->partyAddress[comp->len] = '\0';
|
||||
|
||||
/* Invoke ID stuff */
|
||||
if (&vdata[i])
|
||||
comp = (struct rose_component*)&vdata[i];
|
||||
else return -1;
|
||||
return 0;
|
||||
}
|
||||
while(0);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (i+1 >= len) return -1;
|
||||
if (comp->type && comp->type != ASN1_INTEGER) {
|
||||
pri_message("Don't know what to do if first ROSE component is of type 0x%x\n",comp->type);
|
||||
static int rose_public_party_number_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
|
||||
{
|
||||
int i = 0;
|
||||
struct rose_component *comp = NULL;
|
||||
unsigned char *vdata = data;
|
||||
int ton;
|
||||
|
||||
if (len < 2)
|
||||
return -1;
|
||||
|
||||
do {
|
||||
GET_COMPONENT(comp, i, vdata, len);
|
||||
CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Don't know what to do with PublicPartyNumber ROSE component type 0x%x\n");
|
||||
ASN1_GET_INTEGER(comp, ton);
|
||||
NEXT_COMPONENT(comp, i);
|
||||
ton = typeofnumber_for_q931(pri, ton);
|
||||
|
||||
if(rose_number_digits_decode(pri, call, &vdata[i], len-i, value))
|
||||
return -1;
|
||||
value->ton = ton;
|
||||
|
||||
return 0;
|
||||
|
||||
} while(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int rose_address_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
|
||||
{
|
||||
int i = 0;
|
||||
struct rose_component *comp = NULL;
|
||||
unsigned char *vdata = data;
|
||||
|
||||
do {
|
||||
GET_COMPONENT(comp, i, vdata, len);
|
||||
|
||||
switch(comp->type) {
|
||||
case 0xA0: /* 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 */
|
||||
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 */
|
||||
pri_message("!! NsapEncodedNumber isn't handled\n");
|
||||
return -1;
|
||||
case 0xA3: /* 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 */
|
||||
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 */
|
||||
pri_message("!! privatePartyNumber isn't handled\n");
|
||||
value->npi = PRI_NPI_PRIVATE;
|
||||
return -1;
|
||||
case 0xA8: /* nationalStandardPartyNumber */
|
||||
if (rose_number_digits_decode(pri, call, comp->data, comp->len, value))
|
||||
return -1;
|
||||
value->npi = PRI_NPI_NATIONAL;
|
||||
value->ton = PRI_TON_NATIONAL;
|
||||
break;
|
||||
default:
|
||||
pri_message("!! Unknown Party number component received 0x%X\n", comp->type);
|
||||
return -1;
|
||||
}
|
||||
NEXT_COMPONENT(comp, i);
|
||||
if(i < len)
|
||||
pri_message("!! not all information is handled from Address component\n");
|
||||
return 0;
|
||||
}
|
||||
while (0);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int rose_presented_number_unscreened_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
|
||||
{
|
||||
int i = 0;
|
||||
struct rose_component *comp = NULL;
|
||||
unsigned char *vdata = data;
|
||||
|
||||
/* Fill in default values */
|
||||
value->ton = PRI_TON_UNKNOWN;
|
||||
value->npi = PRI_NPI_E163_E164;
|
||||
value->pres = -1; /* Data is not available */
|
||||
|
||||
do {
|
||||
GET_COMPONENT(comp, i, vdata, len);
|
||||
|
||||
switch(comp->type) {
|
||||
case 0xA0: /* [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 */
|
||||
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 */
|
||||
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 */
|
||||
value->pres = PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
|
||||
return rose_address_decode(pri, call, comp->data, comp->len, value);
|
||||
default:
|
||||
pri_message("Invalid PresentedNumberUnscreened component 0x%X\n", comp->type);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
i += comp->len + 2;
|
||||
while (0);
|
||||
|
||||
/* Operation Tag */
|
||||
if (&vdata[i])
|
||||
comp = (struct rose_component*)&vdata[i];
|
||||
else return -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (i+1 >= len) return -1;
|
||||
if (comp->type && comp->type != ASN1_INTEGER) {
|
||||
pri_message("Don't know what to do if second ROSE component is of type 0x%x\n",comp->type);
|
||||
return -1;
|
||||
static int rose_diverting_leg_information2_decode(struct pri *pri, q931_call *call, unsigned char *data, int len)
|
||||
{
|
||||
int i = 0;
|
||||
int diversion_counter;
|
||||
int diversion_reason;
|
||||
struct addressingdataelements_presentednumberunscreened divertingNr;
|
||||
struct addressingdataelements_presentednumberunscreened originalCalledNr;
|
||||
struct rose_component *comp = NULL;
|
||||
unsigned char *vdata = data;
|
||||
|
||||
do {
|
||||
/* diversionCounter stuff */
|
||||
GET_COMPONENT(comp, i, vdata, len);
|
||||
CHECK_COMPONENT(comp, ASN1_INTEGER, "Don't know what to do it diversionCounter is of type 0x%x\n");
|
||||
ASN1_GET_INTEGER(comp, diversion_counter);
|
||||
NEXT_COMPONENT(comp, i);
|
||||
|
||||
/* diversionReason stuff */
|
||||
GET_COMPONENT(comp, i, vdata, len);
|
||||
CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Invalid diversionReason type 0x%X of ROSE divertingLegInformation2 component received\n");
|
||||
ASN1_GET_INTEGER(comp, diversion_reason);
|
||||
NEXT_COMPONENT(comp, i);
|
||||
|
||||
diversion_reason = redirectingreason_for_q931(pri, diversion_reason);
|
||||
|
||||
#ifdef DEBUG
|
||||
if(pri->debug)
|
||||
pri_message(" Redirection reason: %d, total diversions: %d\n", diversion_reason, diversion_counter);
|
||||
#endif
|
||||
|
||||
for(; i < len; NEXT_COMPONENT(comp, i)) {
|
||||
GET_COMPONENT(comp, i, vdata, len);
|
||||
switch(comp->type) {
|
||||
case 0xA1: /* divertingNr: PresentedNumberUnscreened */
|
||||
if(rose_presented_number_unscreened_decode(pri, call, comp->data, comp->len, &divertingNr) != 0)
|
||||
return -1;
|
||||
#ifdef DEBUG
|
||||
if (pri->debug) {
|
||||
pri_message(" Received divertingNr '%s'\n", divertingNr.partyAddress);
|
||||
pri_message(" ton = %d, pres = %d, npi = %d\n", divertingNr.ton, divertingNr.pres, divertingNr.npi);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 0xA2: /* originalCalledNr: PresentedNumberUnscreened */
|
||||
if(rose_presented_number_unscreened_decode(pri, call, comp->data, comp->len, &originalCalledNr) != 0)
|
||||
return -1;
|
||||
#ifdef DEBUG
|
||||
if (pri->debug) {
|
||||
pri_message(" Received originalCalledNr '%s'\n", originalCalledNr.partyAddress);
|
||||
pri_message(" ton = %d, pres = %d, npi = %d\n", originalCalledNr.ton, originalCalledNr.pres, originalCalledNr.npi);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
pri_message("!! Invalid DivertingLegInformation2 component received 0x%X\n", comp->type);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (i < len)
|
||||
return -1; /* Aborted before */
|
||||
|
||||
if (divertingNr.pres >= 0) {
|
||||
call->redirectingplan = divertingNr.npi;
|
||||
call->redirectingpres = divertingNr.pres;
|
||||
call->redirectingreason = diversion_reason;
|
||||
strncpy(call->redirectingnum, divertingNr.partyAddress, sizeof(call->redirectingnum)-1);
|
||||
call->redirectingnum[sizeof(call->redirectingnum)-1] = '\0';
|
||||
}
|
||||
else if (originalCalledNr.pres >= 0) {
|
||||
call->redirectingplan = originalCalledNr.npi;
|
||||
call->redirectingpres = originalCalledNr.pres;
|
||||
call->redirectingreason = diversion_reason;
|
||||
strncpy(call->redirectingnum, originalCalledNr.partyAddress, sizeof(call->redirectingnum)-1);
|
||||
call->redirectingnum[sizeof(call->redirectingnum)-1] = '\0';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
i += comp->len + 2;
|
||||
while (0);
|
||||
|
||||
if (i >= len)
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Arguement Tag */
|
||||
if (&vdata[i])
|
||||
comp = (struct rose_component*)&vdata[i];
|
||||
else return -1;
|
||||
int rose_invoke_decode(struct pri *pri, q931_call *call, unsigned char *data, int len)
|
||||
{
|
||||
int i = 0;
|
||||
int operation_tag;
|
||||
unsigned char *vdata = data;
|
||||
struct rose_component *comp = NULL, *invokeid = NULL, *operationid = NULL;
|
||||
|
||||
if (comp->type) {
|
||||
switch (comp->type) {
|
||||
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");
|
||||
invokeid = comp;
|
||||
NEXT_COMPONENT(comp, i);
|
||||
|
||||
/* Operation Tag */
|
||||
GET_COMPONENT(comp, i, vdata, len);
|
||||
CHECK_COMPONENT(comp, ASN1_INTEGER, "Don't know what to do if second ROSE component is of type 0x%x\n");
|
||||
operationid = comp;
|
||||
ASN1_GET_INTEGER(comp, operation_tag);
|
||||
NEXT_COMPONENT(comp, i);
|
||||
|
||||
/* No argument - return with error */
|
||||
if (i >= len)
|
||||
return -1;
|
||||
|
||||
/* Arguement Tag */
|
||||
GET_COMPONENT(comp, i, vdata, len);
|
||||
if (!comp->type)
|
||||
return -1;
|
||||
|
||||
#ifdef DEBUG
|
||||
pri_message(" [ Handling operation %d ]\n", operation_tag);
|
||||
#endif
|
||||
switch (operation_tag) {
|
||||
case SS_CNID_CALLINGNAME:
|
||||
#ifdef DEBUG
|
||||
if (pri->debug)
|
||||
pri_message(" Handle Name display operation\n");
|
||||
#endif
|
||||
switch (comp->type) {
|
||||
case ROSE_NAME_PRESENTATION_ALLOWED_SIMPLE:
|
||||
memcpy(call->callername, comp->data, comp->len);
|
||||
call->callername[comp->len] = 0;
|
||||
#ifdef DEBUG
|
||||
if (pri->debug)
|
||||
pri_message(" Received caller name '%s'\n", call->callername);
|
||||
#endif
|
||||
return 0;
|
||||
default:
|
||||
pri_message("Do not handle argument of type 0x%X\n", comp->type);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case ROSE_DIVERTING_LEG_INFORMATION2:
|
||||
#ifdef DEBUG
|
||||
if (pri->debug)
|
||||
pri_message(" Handle DivertingLegInformation2\n");
|
||||
#endif
|
||||
if (comp->type != 0x30) { /* Sequence */
|
||||
pri_message("Invalid DivertingLegInformation2Type argument\n");
|
||||
return -1;
|
||||
}
|
||||
return rose_diverting_leg_information2_decode(pri, call, comp->data, comp->len);
|
||||
default:
|
||||
pri_message("!! Unable to handle ROSE operation %d\n", operation_tag);
|
||||
return -1;
|
||||
}
|
||||
} else return -1;
|
||||
} while(0);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
181
pri_facility.h
181
pri_facility.h
@@ -11,68 +11,161 @@
|
||||
#define _PRI_FACILITY_H
|
||||
|
||||
/* Protocol Profile field */
|
||||
#define ROSE_NETWORK_EXTENSION 0x9F
|
||||
#define Q932_PROTOCOL_ROSE 0x11 /* X.219 & X.229 */
|
||||
#define Q932_PROTOCOL_CMIP 0x12 /* Q.941 */
|
||||
#define Q932_PROTOCOL_ACSE 0x13 /* X.217 & X.227 */
|
||||
#define Q932_PROTOCOL_GAT 0x16
|
||||
#define Q932_PROTOCOL_EXTENSIONS 0x1F
|
||||
|
||||
/* Argument values */
|
||||
#define ROSE_NAME_PRESENTATION_ALLOWED_SIMPLE 0x80
|
||||
#define ROSE_NAME_PRESENTATION_RESTRICTED_NULL 0x87
|
||||
#define ROSE_NAME_NOT_AVAIL 0x84
|
||||
|
||||
/* Divert arguments */
|
||||
#define ROSE_DIVERTING_LEG_INFORMATION2 0x15
|
||||
#define ROSE_NAME_PRESENTATION_ALLOWED_SIMPLE 0x80
|
||||
#define ROSE_NAME_PRESENTATION_RESTRICTED_NULL 0x87
|
||||
#define ROSE_NAME_NOT_AVAIL 0x84
|
||||
|
||||
/* Component types */
|
||||
#define COMP_TYPE_INVOKE 0xA1
|
||||
#define COMP_TYPE_INTERPRETATION 0x8B
|
||||
#define COMP_TYPE_NETWORK_PROTOCOL_PROFILE 0x92
|
||||
#define COMP_TYPE_RETURN_RESULT 0xA2
|
||||
#define COMP_TYPE_RETURN_ERROR 0xA3
|
||||
#define COMP_TYPE_REJECT 0xA4
|
||||
#define COMP_TYPE_NFE 0xAA
|
||||
#define COMP_TYPE_INTERPRETATION 0x8B
|
||||
#define COMP_TYPE_NETWORK_PROTOCOL_PROFILE 0x92
|
||||
#define COMP_TYPE_INVOKE 0xA1
|
||||
#define COMP_TYPE_RETURN_RESULT 0xA2
|
||||
#define COMP_TYPE_RETURN_ERROR 0xA3
|
||||
#define COMP_TYPE_REJECT 0xA4
|
||||
#define COMP_TYPE_NFE 0xAA
|
||||
|
||||
/* Operation ID values */
|
||||
/* Q.952 ROSE operations */
|
||||
#define ROSE_DIVERTING_LEG_INFORMATION1 18
|
||||
#define ROSE_DIVERTING_LEG_INFORMATION2 15
|
||||
#define ROSE_DIVERTING_LEG_INFORMATION3 19
|
||||
/* Q.SIG operations */
|
||||
#define SS_CNID_CALLINGNAME 0
|
||||
#define SS_DIVERTING_LEG_INFORMATION2 22
|
||||
#define SS_MWI_ACTIVATE 80
|
||||
#define SS_MWI_DEACTIVATE 81
|
||||
#define SS_MWI_INTERROGATE 82
|
||||
|
||||
/* ROSE definitions and data structures */
|
||||
#define INVOKE_IDENTIFIER 0x02
|
||||
#define INVOKE_LINKED_IDENTIFIER 0x80
|
||||
#define INVOKE_NULL_IDENTIFIER __USE_ASN1_NULL
|
||||
#define INVOKE_IDENTIFIER 0x02
|
||||
#define INVOKE_LINKED_IDENTIFIER 0x80
|
||||
#define INVOKE_NULL_IDENTIFIER __USE_ASN1_NULL
|
||||
|
||||
/* ASN.1 Data types */
|
||||
#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_UTF8STRING 0x0c
|
||||
#define ASN1_SEQUENCE 0x10
|
||||
#define ASN1_SET 0x11
|
||||
#define ASN1_NUMERICSTRING 0x12
|
||||
#define ASN1_PRINTABLESTRING 0x13
|
||||
#define ASN1_TELETEXSTRING 0x14
|
||||
#define ASN1_IA5STRING 0x16
|
||||
#define ASN1_UTCTIME 0x17
|
||||
#define ASN1_GENERALIZEDTIME 0x18
|
||||
#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_EXTERN 0x08
|
||||
#define ASN1_REAL 0x09
|
||||
#define ASN1_ENUMERATED 0x0a
|
||||
#define ASN1_EMBEDDEDPDV 0x0b
|
||||
#define ASN1_UTF8STRING 0x0c
|
||||
#define ASN1_RELATIVEOBJECTID 0x0d
|
||||
/* 0x0e & 0x0f are reserved for future ASN.1 editions */
|
||||
#define ASN1_SEQUENCE 0x10
|
||||
#define ASN1_SET 0x11
|
||||
#define ASN1_NUMERICSTRING 0x12
|
||||
#define ASN1_PRINTABLESTRING 0x13
|
||||
#define ASN1_TELETEXSTRING 0x14
|
||||
#define ASN1_IA5STRING 0x16
|
||||
#define ASN1_UTCTIME 0x17
|
||||
#define ASN1_GENERALIZEDTIME 0x18
|
||||
|
||||
#define INVOKE_OPERATION_INT __USE_ASN1_INTEGER
|
||||
#define INVOKE_OBJECT_ID __USE_ASN1_OBJECTIDENTIFIER
|
||||
|
||||
#define INVOKE_OPERATION_INT __USE_ASN1_INTEGER
|
||||
#define INVOKE_OBJECT_ID __USE_ASN1_OBJECTIDENTIFIER
|
||||
/* Q.952 Divert cause */
|
||||
#define Q952_DIVERT_REASON_UNKNOWN 0x00
|
||||
#define Q952_DIVERT_REASON_CFU 0x01
|
||||
#define Q952_DIVERT_REASON_CFB 0x02
|
||||
#define Q952_DIVERT_REASON_CFNR 0x03
|
||||
#define Q952_DIVERT_REASON_CD 0x04
|
||||
#define Q952_DIVERT_REASON_IMMEDIATE 0x05
|
||||
/* Q.SIG Divert cause. Listed in ECMA-174 */
|
||||
#define QSIG_DIVERT_REASON_UNKNOWN 0x00 /* Call forward unknown reason */
|
||||
#define QSIG_DIVERT_REASON_CFU 0x01 /* Call Forward Unconditional (other reason) */
|
||||
#define QSIG_DIVERT_REASON_CFB 0x02 /* Call Forward Busy */
|
||||
#define QSIG_DIVERT_REASON_CFNR 0x03 /* Call Forward No Reply */
|
||||
|
||||
/* Divert cause */
|
||||
#define DIVERT_REASON_UNKNOWN 0x00
|
||||
#define DIVERT_REASON_CFU 0x01
|
||||
#define DIVERT_REASON_CFB 0x02
|
||||
#define DIVERT_REASON_CFNR 0x03
|
||||
/* Q.932 Type of number */
|
||||
#define Q932_TON_UNKNOWN 0x00
|
||||
#define Q932_TON_INTERNATIONAL 0x01
|
||||
#define Q932_TON_NATIONAL 0x02
|
||||
#define Q932_TON_NET_SPECIFIC 0x03
|
||||
#define Q932_TON_SUBSCRIBER 0x04
|
||||
#define Q932_TON_ABBREVIATED 0x06
|
||||
|
||||
struct rose_component {
|
||||
u_int8_t type;
|
||||
u_int8_t len;
|
||||
u_int8_t data[0];
|
||||
u_int8_t type;
|
||||
u_int8_t len;
|
||||
u_int8_t data[0];
|
||||
};
|
||||
|
||||
#define GET_COMPONENT(component, idx, ptr, length) \
|
||||
if ((idx)+2 >= (length)) \
|
||||
break; \
|
||||
(component) = (struct rose_component*)&((ptr)[idx]); \
|
||||
if ((idx)+(component)->len+2 > (length)) { \
|
||||
if ((component)->len != 128) \
|
||||
pri_message("Length (%d) of 0x%X component is too long\n", (component)->len, (component)->type); \
|
||||
}
|
||||
/*
|
||||
pri_message("XX Got component %d (0x%02X), length %d\n", (component)->type, (component)->type, (component)->len); \
|
||||
if ((component)->len > 0) { \
|
||||
int zzz; \
|
||||
pri_message("XX Data:"); \
|
||||
for (zzz = 0; zzz < (component)->len; ++zzz) \
|
||||
pri_message(" %02X", (component)->data[zzz]); \
|
||||
pri_message("\n"); \
|
||||
}
|
||||
*/
|
||||
|
||||
#define NEXT_COMPONENT(component, idx) \
|
||||
(idx) += (component)->len + 2
|
||||
|
||||
#define SUB_COMPONENT(component, idx) \
|
||||
(idx) += 2
|
||||
|
||||
#define CHECK_COMPONENT(component, comptype, message) \
|
||||
if ((component)->type && ((component)->type&0x1f) != (comptype)) { \
|
||||
pri_message((message), (component)->type); \
|
||||
break; \
|
||||
}
|
||||
|
||||
#define ASN1_GET_INTEGER(component, variable) \
|
||||
{ \
|
||||
int comp_idx; \
|
||||
(variable) = 0; \
|
||||
for (comp_idx = 0; comp_idx < (component)->len; ++comp_idx) \
|
||||
(variable) = ((variable) << 8) | (component)->data[comp_idx]; \
|
||||
}
|
||||
|
||||
#define ASN1_ADD_SIMPLE(component, comptype, ptr, idx) \
|
||||
(component) = (struct rose_component *)&((ptr)[(idx)]); \
|
||||
(component)->type = (comptype); \
|
||||
(component)->len = 0; \
|
||||
(idx) += 2;
|
||||
|
||||
#define ASN1_ADD_BYTECOMP(component, comptype, ptr, idx, value) \
|
||||
(component) = (struct rose_component *)&((ptr)[(idx)]); \
|
||||
(component)->type = (comptype); \
|
||||
(component)->len = 1; \
|
||||
(component)->data[0] = (value); \
|
||||
(idx) += 3;
|
||||
|
||||
#define ASN1_PUSH(stack, stackpointer, component) \
|
||||
(stack)[(stackpointer)++] = (component);
|
||||
|
||||
#define ASN1_FIXUP(stack, stackpointer, data, idx) \
|
||||
--(stackpointer); \
|
||||
(stack)[(stackpointer)]->len = (unsigned char *)&((data)[(idx)]) - (unsigned char *)(stack)[(stackpointer)] - 2;
|
||||
|
||||
/* Decoder fo the invoke part of a ROSE request
|
||||
It currently only support calling name decode */
|
||||
extern int rose_invoke_decode(struct q931_call *call, unsigned char *data, int len);
|
||||
extern int rose_invoke_decode(struct pri *pri, struct q931_call *call, unsigned char *data, int len);
|
||||
extern int asn1_string_encode(unsigned char asn1_type, void *data, int len, int max_len, void *src, int src_len);
|
||||
int typeofnumber_from_q931(struct pri *pri, int ton);
|
||||
int redirectingreason_from_q931(struct pri *pri, int redirectingreason);
|
||||
|
||||
#endif /* _PRI_FACILITY_H */
|
||||
|
||||
@@ -103,6 +103,8 @@ struct pri {
|
||||
unsigned int q931_txcount;
|
||||
unsigned int q931_rxcount;
|
||||
#endif
|
||||
|
||||
unsigned char last_invoke; /* Last ROSE invoke ID */
|
||||
};
|
||||
|
||||
struct pri_sr {
|
||||
|
||||
295
q931.c
295
q931.c
@@ -1049,68 +1049,231 @@ static FUNC_RECV(receive_progress_indicator)
|
||||
|
||||
static FUNC_SEND(transmit_facility)
|
||||
{
|
||||
int i = 0;
|
||||
struct rose_component *comp;
|
||||
int i = 0, j, first_i, compsp = 0;
|
||||
struct rose_component *comp, *compstk[10];
|
||||
unsigned char namelen = strlen(call->callername);
|
||||
|
||||
if (namelen > 15)
|
||||
if ((pri->switchtype == PRI_SWITCH_NI2) && (namelen > 15))
|
||||
namelen = 15; /* According to GR-1367, for NI2 switches it can't be > 15 characters */
|
||||
if ((namelen > 0) && ((pri->switchtype == PRI_SWITCH_QSIG) ||
|
||||
((pri->switchtype == PRI_SWITCH_NI2) && (pri->localtype == PRI_NETWORK)))) {
|
||||
ie->data[i] = ROSE_NETWORK_EXTENSION;
|
||||
i++;
|
||||
/* Interpretation component */
|
||||
comp = (struct rose_component*)&ie->data[i];
|
||||
comp->type = COMP_TYPE_INTERPRETATION;
|
||||
comp->len = 0x01;
|
||||
comp->data[0] = 0x00; /* Discard unrecognized invokes */
|
||||
do {
|
||||
first_i = i;
|
||||
ie->data[i] = 0x80 | Q932_PROTOCOL_EXTENSIONS;
|
||||
i++;
|
||||
/* Interpretation component */
|
||||
ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, ie->data, i, 0x00 /* Discard unrecognized invokes */);
|
||||
|
||||
i += 3;
|
||||
comp = (struct rose_component*)&ie->data[i];
|
||||
/* Invoke ID */
|
||||
comp->type = COMP_TYPE_INVOKE;
|
||||
comp->len = 3 /* sizeof Invoke ID */
|
||||
+ 3 /* sizeof Operation tag */
|
||||
+ 2 /* first two bytes of the Arguement section */
|
||||
+ namelen;
|
||||
/* Invoke ID */
|
||||
ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, ie->data, i);
|
||||
ASN1_PUSH(compstk, compsp, comp);
|
||||
|
||||
i += 2;
|
||||
comp = (struct rose_component*)&ie->data[i];
|
||||
/* Invoke component contents */
|
||||
/* Invoke ID */
|
||||
comp->type = ASN1_INTEGER;
|
||||
comp->len = 0x01;
|
||||
comp->data[0] = 0x01; /* Invoke ID value */
|
||||
i += 3;
|
||||
comp = (struct rose_component*)&ie->data[i];
|
||||
/* Operation Tag */
|
||||
comp->type = ASN1_INTEGER;
|
||||
comp->len = 0x01;
|
||||
comp->data[0] = 0x00; /* Calling name */
|
||||
i += 3;
|
||||
comp = (struct rose_component*)&ie->data[i];
|
||||
/* Arugement Tag */
|
||||
comp->type = ROSE_NAME_PRESENTATION_ALLOWED_SIMPLE;
|
||||
comp->len = namelen;
|
||||
i += 2;
|
||||
memcpy(comp->data, call->callername, namelen);
|
||||
i += namelen;
|
||||
return i+2 /* 2 = length of IE header */;
|
||||
/* Invoke component contents */
|
||||
/* Invoke ID */
|
||||
ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, ie->data, i, ++pri->last_invoke);
|
||||
|
||||
/* Operation Tag */
|
||||
ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, ie->data, i, SS_CNID_CALLINGNAME);
|
||||
|
||||
/* Arugement Tag */
|
||||
j = asn1_string_encode(ROSE_NAME_PRESENTATION_ALLOWED_SIMPLE, &ie->data[i], len - i, 15, call->callername, namelen);
|
||||
if (j < 0) {
|
||||
i = first_i;
|
||||
break;
|
||||
}
|
||||
i += j;
|
||||
|
||||
/* Fix length of stacked components */
|
||||
while(compsp > 0) {
|
||||
ASN1_FIXUP(compstk, compsp, ie->data, i);
|
||||
}
|
||||
} while (0);
|
||||
}
|
||||
if (/*(pri->switchtype == PRI_SWITCH_EUROISDN_E1) &&*/ call->redirectingnum && strlen(call->redirectingnum)) {
|
||||
if (!(first_i = i)) {
|
||||
/* Add protocol information header */
|
||||
ie->data[i++] = 0x80 | Q932_PROTOCOL_ROSE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
/* ROSE invoke component */
|
||||
ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, ie->data, i);
|
||||
ASN1_PUSH(compstk, compsp, comp);
|
||||
|
||||
/* ROSE invokeId component */
|
||||
ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, ie->data, i, ++pri->last_invoke);
|
||||
|
||||
/* ROSE operationId component */
|
||||
ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, ie->data, i, ROSE_DIVERTING_LEG_INFORMATION2);
|
||||
|
||||
/* ROSE ARGUMENT component */
|
||||
ASN1_ADD_SIMPLE(comp, 0x30, ie->data, i);
|
||||
|
||||
/* ROSE DivertingLegInformation2.diversionCounter component */
|
||||
/* Always is 1 because other isn't available in the current design */
|
||||
ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, ie->data, i, 1);
|
||||
|
||||
/* ROSE DivertingLegInformation2.diversionReason component */
|
||||
ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, ie->data, i, redirectingreason_from_q931(pri, call->redirectingreason));
|
||||
|
||||
/* ROSE DivertingLegInformation2.divertingNr component */
|
||||
ASN1_ADD_SIMPLE(comp, 0xA1, ie->data, 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, ie->data, i);
|
||||
ASN1_PUSH(compstk, compsp, comp);
|
||||
|
||||
/* NPI of redirected number is not supported in the current design */
|
||||
ASN1_ADD_SIMPLE(comp, 0xA1, ie->data, i);
|
||||
ASN1_PUSH(compstk, compsp, comp);
|
||||
|
||||
ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, ie->data, i, typeofnumber_from_q931(pri, call->redirectingplan >> 4));
|
||||
|
||||
j = asn1_string_encode(ASN1_NUMERICSTRING, &ie->data[i], len - i, 20, call->redirectingnum, strlen(call->redirectingnum));
|
||||
if (j < 0) {
|
||||
i = first_i;
|
||||
goto finish2;
|
||||
}
|
||||
i += j;
|
||||
ASN1_FIXUP(compstk, compsp, ie->data, i);
|
||||
ASN1_FIXUP(compstk, compsp, ie->data, i);
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
case PRES_PROHIB_USER_NUMBER_PASSED_SCREEN:
|
||||
case PRES_PROHIB_USER_NUMBER_NOT_SCREENED:
|
||||
ASN1_ADD_SIMPLE(comp, 0x81, ie->data, 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, ie->data, 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, ie->data, i);
|
||||
break;
|
||||
}
|
||||
ASN1_FIXUP(compstk, compsp, ie->data, i);
|
||||
|
||||
/* ROSE DivertingLegInformation2.originalCalledNr component */
|
||||
/* This information isn't supported by current design - duplicate divertingNr */
|
||||
ASN1_ADD_SIMPLE(comp, 0xA2, ie->data, 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, ie->data, i);
|
||||
ASN1_PUSH(compstk, compsp, comp);
|
||||
|
||||
ASN1_ADD_SIMPLE(comp, 0xA1, ie->data, i);
|
||||
ASN1_PUSH(compstk, compsp, comp);
|
||||
|
||||
ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, ie->data, i, typeofnumber_from_q931(pri, call->redirectingplan >> 4));
|
||||
|
||||
j = asn1_string_encode(ASN1_NUMERICSTRING, &ie->data[i], len - i, 20, call->redirectingnum, strlen(call->redirectingnum));
|
||||
if (j < 0) {
|
||||
i = first_i;
|
||||
goto finish2;
|
||||
}
|
||||
i += j;
|
||||
ASN1_FIXUP(compstk, compsp, ie->data, i);
|
||||
ASN1_FIXUP(compstk, compsp, ie->data, i);
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
case PRES_PROHIB_USER_NUMBER_PASSED_SCREEN:
|
||||
case PRES_PROHIB_USER_NUMBER_NOT_SCREENED:
|
||||
ASN1_ADD_SIMPLE(comp, 0x81, ie->data, 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, ie->data, 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, ie->data, i);
|
||||
break;
|
||||
}
|
||||
ASN1_FIXUP(compstk, compsp, ie->data, i);
|
||||
|
||||
/* Fix length of stacked components */
|
||||
while(compsp > 0) {
|
||||
ASN1_FIXUP(compstk, compsp, ie->data, i);
|
||||
}
|
||||
}
|
||||
finish2:
|
||||
return (i ? i+2 : 0);
|
||||
}
|
||||
|
||||
static FUNC_RECV(receive_facility)
|
||||
{
|
||||
int i = 0;
|
||||
int protocol, next_protocol;
|
||||
struct rose_component *comp = NULL;
|
||||
enum {
|
||||
Q932_STATE_NFE, /* Network facility extension */
|
||||
Q932_STATE_NPP, /* Network protocol profile */
|
||||
Q932_STATE_INTERPRETATION, /* Interpretation component */
|
||||
Q932_STATE_SERVICE /* Service component(s) */
|
||||
} state = Q932_STATE_SERVICE;
|
||||
#define Q932_HANDLE_PROC(component, my_state, name, handler) \
|
||||
case component: \
|
||||
if(state > my_state) { \
|
||||
pri_error("!! %s component received in wrong place\n"); \
|
||||
break; \
|
||||
} \
|
||||
state = my_state; \
|
||||
if (pri->debug) \
|
||||
pri_message("Handle Q.932 %s component\n", name); \
|
||||
(handler)(pri, call, comp->data, comp->len); \
|
||||
break;
|
||||
#define Q932_HANDLE_NULL(component, my_state, name, handle) \
|
||||
case component: \
|
||||
if(state > my_state) { \
|
||||
pri_error("!! %s component received in wrong place\n"); \
|
||||
break; \
|
||||
} \
|
||||
state = my_state; \
|
||||
if (pri->debug) \
|
||||
pri_message("Q.932 %s component is not handled\n", name); \
|
||||
break;
|
||||
|
||||
if (ie->len < 1)
|
||||
return -1;
|
||||
|
||||
if(ie->data[i] != 0x9F) {
|
||||
if (pri->debug) pri_message("!! Don't know how to handle Service Discriminator of type 0x%X\n", ie->data[i]);
|
||||
if ((ie->data[i] & 0xe0) != 0x80) {
|
||||
pri_error ("!! Invalid Protocol Profile field 0x%X\n", ie->data[i]);
|
||||
return -1;
|
||||
}
|
||||
switch(next_protocol = protocol = (ie->data[i] & 0x1f)) {
|
||||
case Q932_PROTOCOL_CMIP:
|
||||
case Q932_PROTOCOL_ACSE:
|
||||
if (pri->debug)
|
||||
pri_message("!! Don't know how to handle Q.932 Protocol Profile of type 0x%X\n", protocol);
|
||||
return -1;
|
||||
case Q932_PROTOCOL_EXTENSIONS:
|
||||
state = Q932_STATE_NFE;
|
||||
next_protocol = Q932_PROTOCOL_ROSE;
|
||||
break;
|
||||
case Q932_PROTOCOL_ROSE:
|
||||
break;
|
||||
default:
|
||||
pri_error("!! Invalid Q.932 Protocol Profile of type 0x%X received\n", protocol);
|
||||
return -1;
|
||||
}
|
||||
i++;
|
||||
@@ -1121,20 +1284,50 @@ static FUNC_RECV(receive_facility)
|
||||
while ((i+1 < ie->len) && (&ie->data[i])) {
|
||||
comp = (struct rose_component*)&ie->data[i];
|
||||
if (comp->type) {
|
||||
switch (comp->type) {
|
||||
case COMP_TYPE_INTERPRETATION:
|
||||
if (pri->debug) pri_message("Handle ROSE interpretation component\n");
|
||||
break;
|
||||
case COMP_TYPE_INVOKE:
|
||||
rose_invoke_decode(call, comp->data, comp->len);
|
||||
break;
|
||||
if (protocol == Q932_PROTOCOL_EXTENSIONS) {
|
||||
switch (comp->type) {
|
||||
Q932_HANDLE_NULL(COMP_TYPE_INTERPRETATION, Q932_STATE_INTERPRETATION, "Interpretation", NULL);
|
||||
Q932_HANDLE_NULL(COMP_TYPE_NFE, Q932_STATE_NFE, "Network facility extensions", NULL);
|
||||
Q932_HANDLE_NULL(COMP_TYPE_NETWORK_PROTOCOL_PROFILE, Q932_STATE_NPP, "Network protocol profile", NULL);
|
||||
default:
|
||||
if (pri->debug) pri_message("Don't know how to handle ROSE component of type 0x%X\n", comp->type);
|
||||
protocol = next_protocol;
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch (protocol) {
|
||||
case Q932_PROTOCOL_ROSE:
|
||||
switch (comp->type) {
|
||||
Q932_HANDLE_PROC(COMP_TYPE_INVOKE, Q932_STATE_SERVICE, "ROSE Invoke", rose_invoke_decode);
|
||||
Q932_HANDLE_NULL(COMP_TYPE_RETURN_RESULT, Q932_STATE_SERVICE, "ROSE return result", NULL);
|
||||
Q932_HANDLE_NULL(COMP_TYPE_RETURN_ERROR, Q932_STATE_SERVICE, "ROSE return error", NULL);
|
||||
Q932_HANDLE_NULL(COMP_TYPE_REJECT, Q932_STATE_SERVICE, "ROSE reject", NULL);
|
||||
default:
|
||||
if (pri->debug)
|
||||
pri_message("Don't know how to handle ROSE component of type 0x%X\n", comp->type);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Q932_PROTOCOL_CMIP:
|
||||
switch (comp->type) {
|
||||
default:
|
||||
if (pri->debug)
|
||||
pri_message("Don't know how to handle CMIP component of type 0x%X\n", comp->type);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Q932_PROTOCOL_ACSE:
|
||||
switch (comp->type) {
|
||||
default:
|
||||
if (pri->debug)
|
||||
pri_message("Don't know how to handle ACSE component of type 0x%X\n", comp->type);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
i += (comp->len + 2);
|
||||
}
|
||||
#undef Q932_HANDLE
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
17
testprilib.c
17
testprilib.c
@@ -75,6 +75,7 @@ static void event1(struct pri *pri, pri_event *e)
|
||||
int x;
|
||||
static q931_call *calls[TEST_CALLS];
|
||||
char name[256], num[256], dest[256];
|
||||
struct pri_sr *sr;
|
||||
switch(e->gen.e) {
|
||||
case PRI_EVENT_DCHAN_UP:
|
||||
printf("Network is up. Sending blast of calls!\n");
|
||||
@@ -84,11 +85,25 @@ static void event1(struct pri *pri, pri_event *e)
|
||||
sprintf(dest, "60%02d", x + 1);
|
||||
if (!(calls[x] = pri_new_call(pri))) {
|
||||
perror("pri_new_call");
|
||||
} else if (pri_call(pri, calls[x], PRI_TRANS_CAP_DIGITAL, x + 1, 1, 1, num,
|
||||
continue;
|
||||
}
|
||||
#if 0
|
||||
sr = pri_sr_new();
|
||||
pri_sr_set_channel(sr, x, 0, 0);
|
||||
pri_sr_set_bearer(sr, 0, PRI_LAYER_1_ULAW);
|
||||
pri_sr_set_called(sr, dest, PRI_NATIONAL_ISDN, 1);
|
||||
pri_sr_set_caller(sr, num, name, PRI_NATIONAL_ISDN, PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN);
|
||||
pri_sr_set_redirecting(sr, num, PRI_NATIONAL_ISDN, PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, PRI_REDIR_UNCONDITIONAL);
|
||||
if (pri_setup(pri, calls[x], sr))
|
||||
perror("pri_setup");
|
||||
pri_sr_free(sr);
|
||||
#else
|
||||
if (pri_call(pri, calls[x], PRI_TRANS_CAP_DIGITAL, x + 1, 1, 1, num,
|
||||
PRI_NATIONAL_ISDN, name, PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN,
|
||||
dest, PRI_NATIONAL_ISDN, PRI_LAYER_1_ULAW)) {
|
||||
perror("pri_call");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
printf("Setup %d calls!\n", TEST_CALLS);
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user