From e4fbf8c3888bc26497f95118662e6ce1383c233e Mon Sep 17 00:00:00 2001 From: Matthew Fredrickson Date: Wed, 6 Apr 2005 19:42:41 +0000 Subject: [PATCH] BIG libpri-matt merge. Adding new event information and fixing the parsing routing for DivertingLegInformation2 so that it can work with indefinite length-encoded ASN.1 parameters git-svn-id: https://origsvn.digium.com/svn/libpri/trunk@209 2fbb986a-6c06-0410-b554-c9c1f0a7f128 --- libpri.h | 4 ++ pri_facility.c | 115 ++++++++++++++++++++++++++++++++++++++----------- pri_facility.h | 6 +++ pri_internal.h | 11 ++++- q931.c | 11 +++++ 5 files changed, 120 insertions(+), 27 deletions(-) diff --git a/libpri.h b/libpri.h index 675a097..e4e7252 100755 --- a/libpri.h +++ b/libpri.h @@ -305,6 +305,7 @@ typedef struct pri_event_ring { int ani2; /* ANI II */ char callednum[256]; /* Called number */ char redirectingnum[256]; /* Redirecting number */ + char redirectingname[256]; /* Redirecting name */ int redirectingreason; /* Reason for redirect */ char useruserinfo[256]; /* User->User info */ int flexible; /* Are we flexible with our channel selection? */ @@ -316,6 +317,9 @@ typedef struct pri_event_ring { char callingsubaddr[256]; /* Calling parties subaddress */ int progress; int progressmask; + char origcalledname[256]; + char origcallednum[256]; + int origredirectingreason; } pri_event_ring; typedef struct pri_event_hangup { diff --git a/pri_facility.c b/pri_facility.c index fe8069c..945b8a9 100755 --- a/pri_facility.c +++ b/pri_facility.c @@ -181,6 +181,25 @@ static int typeofnumber_for_q931(struct pri *pri, int ton) } } +int asn1_name_decode(void * data, int len, char *namebuf, int buflen) +{ + struct rose_component *comp = (struct rose_component*)data; + int datalen = 0, res = 0; + + if (comp->len == ASN1_LEN_INDEF) { + datalen = strlen(comp->data); + res = datalen + 2; + } else + datalen = res = comp->len; + + if (datalen > buflen) { + /* Truncate */ + datalen = buflen; + memcpy(namebuf, comp->data, datalen); + } + return res; +} + 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; @@ -204,18 +223,26 @@ static int rose_number_digits_decode(struct pri *pri, q931_call *call, unsigned int i = 0; struct rose_component *comp = NULL; unsigned char *vdata = data; + int datalen = 0; + int res = 0; 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) { + if(comp->len > 20 && comp->len != ASN1_LEN_INDEF) { pri_message("!! Oversized NumberDigits component (%d)\n", comp->len); return -1; } - memcpy(value->partyaddress, comp->data, comp->len); - value->partyaddress[comp->len] = '\0'; + if (comp->len == ASN1_LEN_INDEF) { + datalen = strlen(comp->data); + res = datalen + 2; + } else + res = datalen = comp->len; + + memcpy(value->partyaddress, comp->data, datalen); + value->partyaddress[datalen] = '\0'; - return 0; + return res + 2; } while(0); @@ -228,6 +255,7 @@ static int rose_public_party_number_decode(struct pri *pri, q931_call *call, uns struct rose_component *comp = NULL; unsigned char *vdata = data; int ton; + int res = 0; if (len < 2) return -1; @@ -239,11 +267,12 @@ static int rose_public_party_number_decode(struct pri *pri, q931_call *call, uns NEXT_COMPONENT(comp, i); ton = typeofnumber_for_q931(pri, ton); - if(rose_number_digits_decode(pri, call, &vdata[i], len-i, value)) + res = rose_number_digits_decode(pri, call, &vdata[i], len-i, value); + if (res < 0) return -1; value->ton = ton; - return 0; + return res + 2; } while(0); return -1; @@ -254,19 +283,22 @@ static int rose_address_decode(struct pri *pri, q931_call *call, unsigned char * int i = 0; struct rose_component *comp = NULL; unsigned char *vdata = data; + int res = 0; do { GET_COMPONENT(comp, i, vdata, len); switch(comp->type) { case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* [0] unknownPartyNumber */ - if(rose_number_digits_decode(pri, call, comp->data, comp->len, value)) + res = rose_number_digits_decode(pri, call, comp->data, comp->len, value); + if (res < 0) return -1; value->npi = PRI_NPI_UNKNOWN; value->ton = PRI_TON_UNKNOWN; break; 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) + res = rose_public_party_number_decode(pri, call, comp->data, comp->len, value); + if (res < 0) return -1; value->npi = PRI_NPI_E163_E164; break; @@ -281,7 +313,8 @@ static int rose_address_decode(struct pri *pri, q931_call *call, unsigned char * pri_message("!! dataPartyNumber isn't handled\n"); return -1; case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_4): /* [4] telexPartyNumber */ - if (rose_number_digits_decode(pri, call, comp->data, comp->len, value)) + res = rose_number_digits_decode(pri, call, comp->data, comp->len, value); + if (res < 0) return -1; value->npi = PRI_NPI_F69 /* ??? */; value->ton = PRI_TON_UNKNOWN /* ??? */; @@ -292,7 +325,8 @@ static int rose_address_decode(struct pri *pri, q931_call *call, unsigned char * value->npi = PRI_NPI_PRIVATE; return -1; case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_8): /* [8] nationalStandardPartyNumber */ - if (rose_number_digits_decode(pri, call, comp->data, comp->len, value)) + res = rose_number_digits_decode(pri, call, comp->data, comp->len, value); + if (res < 0) return -1; value->npi = PRI_NPI_NATIONAL; value->ton = PRI_TON_NATIONAL; @@ -304,7 +338,7 @@ static int rose_address_decode(struct pri *pri, q931_call *call, unsigned char * NEXT_COMPONENT(comp, i); if(i < len) pri_message("!! not all information is handled from Address component\n"); - return 0; + return res; } while (0); @@ -328,24 +362,24 @@ static int rose_presented_number_unscreened_decode(struct pri *pri, q931_call *c switch(comp->type) { 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); + return rose_address_decode(pri, call, comp->data, comp->len, value) + 2; 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; + return 2; 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; + return 2; 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); + return rose_address_decode(pri, call, comp->data, comp->len, value) + 2; default: pri_message("Invalid PresentedNumberUnscreened component 0x%X\n", comp->type); } @@ -361,10 +395,12 @@ static int rose_diverting_leg_information2_decode(struct pri *pri, q931_call *ca int i = 0; int diversion_counter; int diversion_reason; + char origcalledname[50] = "", redirectingname[50] = ""; struct addressingdataelements_presentednumberunscreened divertingnr; struct addressingdataelements_presentednumberunscreened originalcallednr; struct rose_component *comp = NULL; unsigned char *vdata = data; + int res = 0; do { /* diversionCounter stuff */ @@ -386,23 +422,43 @@ static int rose_diverting_leg_information2_decode(struct pri *pri, q931_call *ca 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) + switch(comp->type & ASN1_TYPE_MASK) { + case ASN1_TAG_0: + call->origredirectingreason = redirectingreason_for_q931(pri, comp->data[0]); + if (pri->debug & PRI_DEBUG_APDU) + pri_message(" Received reason for original redirection %d\n", call->origredirectingreason); + break; + case ASN1_TAG_1: /* divertingnr: presentednumberunscreened */ + res = rose_presented_number_unscreened_decode(pri, call, comp->data, comp->len, &divertingnr); + /* TODO: Fix indefinite length form hacks */ + comp->len = res; + if (res < 0) return -1; if (pri->debug & PRI_DEBUG_APDU) { pri_message(" Received divertingNr '%s'\n", divertingnr.partyaddress); pri_message(" ton = %d, pres = %d, npi = %d\n", divertingnr.ton, divertingnr.pres, divertingnr.npi); } break; - case 0xA2: /* originalCalledNr: PresentedNumberUnscreened */ - if(rose_presented_number_unscreened_decode(pri, call, comp->data, comp->len, &originalcallednr) != 0) + case ASN1_TAG_2: /* originalCalledNr: PresentedNumberUnscreened */ + res = rose_presented_number_unscreened_decode(pri, call, comp->data, comp->len, &originalcallednr); + if (res < 0) return -1; + comp->len = res; if (pri->debug & PRI_DEBUG_APDU) { pri_message(" Received originalcallednr '%s'\n", originalcallednr.partyaddress); pri_message(" ton = %d, pres = %d, npi = %d\n", originalcallednr.ton, originalcallednr.pres, originalcallednr.npi); } break; + case ASN1_TAG_3: + comp->len = asn1_name_decode(comp->data, comp->len, redirectingname, sizeof(redirectingname)); + if (pri->debug & PRI_DEBUG_APDU) + pri_message(" Received RedirectingName '%s'\n", redirectingname); + break; + case ASN1_TAG_4: + comp->len = asn1_name_decode(comp->data, comp->len, origcalledname, sizeof(origcalledname)); + if (pri->debug & PRI_DEBUG_APDU) + pri_message(" Received Originally Called Name '%s'\n", origcalledname); + break; default: pri_message("!! Invalid DivertingLegInformation2 component received 0x%X\n", comp->type); return -1; @@ -418,12 +474,19 @@ static int rose_diverting_leg_information2_decode(struct pri *pri, q931_call *ca 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'; + if (originalcallednr.pres >= 0) { + call->origcalledplan = originalcallednr.npi; + call->origcalledpres = originalcallednr.pres; + strncpy(call->origcallednum, originalcallednr.partyaddress, sizeof(call->origcallednum)-1); + call->origcallednum[sizeof(call->origcallednum)-1] = '\0'; + } + if (strlen(redirectingname) > 0) { + strncpy(call->redirectingname, redirectingname, sizeof(call->redirectingname)); + call->redirectingname[sizeof(call->redirectingname)-1] = '\0'; + } + if (strlen(origcalledname) > 0) { + strncpy(call->origcalledname, origcalledname, sizeof(call->origcalledname)); + call->origcalledname[sizeof(call->origcalledname)-1] = '\0'; } return 0; } diff --git a/pri_facility.h b/pri_facility.h index 2117ef9..0fd5f87 100755 --- a/pri_facility.h +++ b/pri_facility.h @@ -107,6 +107,9 @@ #define ASN1_CONTEXT_SPECIFIC 0x80 #define ASN1_PRIVATE 0xc0 +/* ASN.1 Length masks */ +#define ASN1_LEN_INDEF 0x80 + #define INVOKE_OPERATION_INT __USE_ASN1_INTEGER #define INVOKE_OBJECT_ID __USE_ASN1_OBJECTIDENTIFIER @@ -225,6 +228,9 @@ extern int rose_invoke_decode(struct pri *pri, struct q931_call *call, unsigned extern int asn1_string_encode(unsigned char asn1_type, void *data, int len, int max_len, void *src, int src_len); +/* Get Name types from ASN.1 */ +extern int asn1_name_decode(void * data, int len, char *namebuf, int buflen); + extern int typeofnumber_from_q931(struct pri *pri, int ton); extern int redirectingreason_from_q931(struct pri *pri, int redirectingreason); diff --git a/pri_internal.h b/pri_internal.h index 56517fd..f8f18c0 100755 --- a/pri_internal.h +++ b/pri_internal.h @@ -211,10 +211,19 @@ struct q931_call { int retranstimer; /* Timer for retransmitting DISC */ int t308_timedout; /* Whether t308 timed out once */ + int redirectingplan; int redirectingpres; int redirectingreason; - char redirectingnum[256]; + char redirectingnum[256]; /* Number of redirecting party */ + char redirectingname[256]; /* Name of redirecting party */ + + /* Filled in cases of multiple diversions */ + int origcalledplan; + int origcalledpres; + int origredirectingreason; /* Original reason for redirect (in cases of multiple redirects) */ + char origcalledname[256]; /* Original name of person being called */ + char origcallednum[256]; /* Orignal number of person being called */ int useruserprotocoldisc; char useruserinfo[256]; diff --git a/q931.c b/q931.c index a5eb761..f037294 100755 --- a/q931.c +++ b/q931.c @@ -3151,7 +3151,13 @@ int q931_receive(struct pri *pri, q931_h *h, int len) c->redirectingplan = -1; c->redirectingpres = -1; c->redirectingreason = -1; + c->origcalledplan = -1; + c->origcalledpres = -1; + c->origredirectingreason = -1; strcpy(c->redirectingnum, ""); + strcpy(c->origcallednum, ""); + strcpy(c->redirectingname, ""); + strcpy(c->origcalledname, ""); c->useruserprotocoldisc = -1; strcpy(c->useruserinfo, ""); c->complete = 0; @@ -3357,8 +3363,13 @@ int q931_receive(struct pri *pri, q931_h *h, int len) pri->ev.ring.calledplan = c->calledplan; strncpy(pri->ev.ring.callingsubaddr, c->callingsubaddr, sizeof(pri->ev.ring.callingsubaddr) - 1); strncpy(pri->ev.ring.callednum, c->callednum, sizeof(pri->ev.ring.callednum) - 1); + strncpy(pri->ev.ring.origcalledname, c->origcalledname, sizeof(pri->ev.ring.origcalledname) - 1); + strncpy(pri->ev.ring.origcallednum, c->origcallednum, sizeof(pri->ev.ring.origcallednum) - 1); strncpy(pri->ev.ring.redirectingnum, c->redirectingnum, sizeof(pri->ev.ring.redirectingnum) - 1); + strncpy(pri->ev.ring.redirectingname, c->redirectingname, sizeof(pri->ev.ring.redirectingname) - 1); strncpy(pri->ev.ring.useruserinfo, c->useruserinfo, sizeof(pri->ev.ring.useruserinfo) - 1); + pri->ev.ring.redirectingreason = c->redirectingreason; + pri->ev.ring.origredirectingreason = c->origredirectingreason; pri->ev.ring.flexible = ! (c->chanflags & FLAG_EXCLUSIVE); pri->ev.ring.cref = c->cr; pri->ev.ring.call = c;