diff --git a/pri_facility.c b/pri_facility.c index 7faf70d..ecefb58 100755 --- a/pri_facility.c +++ b/pri_facility.c @@ -16,56 +16,467 @@ #include #include -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; } diff --git a/pri_facility.h b/pri_facility.h index cbfd46c..8f92754 100755 --- a/pri_facility.h +++ b/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 */ diff --git a/pri_internal.h b/pri_internal.h index 498e046..2645daa 100755 --- a/pri_internal.h +++ b/pri_internal.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 { diff --git a/q931.c b/q931.c index 13b4876..937f9e3 100755 --- a/q931.c +++ b/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; } diff --git a/testprilib.c b/testprilib.c index b27cc53..79373f9 100755 --- a/testprilib.c +++ b/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;