diff options
Diffstat (limited to 'main/libpri/libpri-1.4.9-i14292.patch')
-rw-r--r-- | main/libpri/libpri-1.4.9-i14292.patch | 5668 |
1 files changed, 5668 insertions, 0 deletions
diff --git a/main/libpri/libpri-1.4.9-i14292.patch b/main/libpri/libpri-1.4.9-i14292.patch new file mode 100644 index 0000000000..27ed1b8d43 --- /dev/null +++ b/main/libpri/libpri-1.4.9-i14292.patch @@ -0,0 +1,5668 @@ +Index: .version +=================================================================== +--- a/.version (.../tags/1.4.9) (revision 700) ++++ b/.version (.../team/group/issue14292) (revision 700) +@@ -1 +1 @@ +-1.4.9 ++1.4.9-issue14292 +Index: pri_facility.c +=================================================================== +--- a/pri_facility.c (.../tags/1.4.9) (revision 700) ++++ b/pri_facility.c (.../team/group/issue14292) (revision 700) +@@ -171,7 +171,7 @@ + + struct addressingdataelements_presentednumberunscreened { + char partyaddress[21]; +- char partysubaddress[21]; ++ char notused[21]; + int npi; /* Numbering Plan Indicator */ + int ton; /* Type Of Number */ + int pres; /* Presentation */ +@@ -179,6 +179,15 @@ + + struct addressingdataelements_presentednumberscreened { + char partyaddress[21]; ++ char notused[21]; ++ int npi; /* Numbering Plan Indicator */ ++ int ton; /* Type Of Number */ ++ int pres; /* Presentation */ ++ int scrind; /* Screening Indicator */ ++}; ++ ++struct addressingdataelements_presentedaddressscreened { ++ char partyaddress[21]; + char partysubaddress[21]; + int npi; /* Numbering Plan Indicator */ + int ton; /* Type Of Number */ +@@ -186,6 +195,35 @@ + int scrind; /* Screening Indicator */ + }; + ++struct addressingdataelements_addressscreened { ++ char partyaddress[21]; ++ char partysubaddress[21]; ++ int npi; /* Numbering Plan Indicator */ ++ int ton; /* Type Of Number */ ++ int notused; ++ int scrind; /* Screening Indicator */ ++}; ++ ++struct addressingdataelements_partysubaddress { ++ char notused[21]; ++ char partysubaddress[21]; ++}; ++ ++struct nameelements_name { ++ char name[51]; ++ int characterset; ++ int namepres; ++}; ++ ++struct nameelements_nameset { ++ char name[51]; ++ int characterset; ++}; ++ ++struct nameelements_namedata { ++ char name[51]; ++}; ++ + #define PRI_CHECKOVERFLOW(size) \ + if (msgptr - message + (size) >= sizeof(message)) { \ + *msgptr = '\0'; \ +@@ -225,6 +263,92 @@ + } + #undef PRI_CHECKOVERFLOW + ++static const char *namepres_to_str(int namepres) ++{ ++ return (namepres == 0) ? "Restricted" : "Allowed"; ++} ++ ++static const char *characterset_to_str(int characterset) ++{ ++ switch (characterset) { ++ case CHARACTER_SET_UNKNOWN: ++ return "Unknown"; ++ case CHARACTER_SET_ISO8859_1: ++ return "ISO8859-1"; ++ case CHARACTER_SET_ISO8859_2: ++ return "ISO8859-2"; ++ case CHARACTER_SET_ISO8859_3: ++ return "ISO8859-3"; ++ case CHARACTER_SET_ISO8859_4: ++ return "ISO8859-4"; ++ case CHARACTER_SET_ISO8859_5: ++ return "ISO8859-5"; ++ case CHARACTER_SET_ISO8859_7: ++ return "ISO8859-7"; ++ default: ++ return "illegal value"; ++ } ++} ++ ++static const char *diversionreason_to_str(struct pri *pri, int diversionreason) ++{ ++ if (pri->switchtype == PRI_SWITCH_QSIG) { ++ switch (diversionreason) { ++ case QSIG_DIVERT_REASON_UNKNOWN: ++ return "Unknown"; ++ case QSIG_DIVERT_REASON_CFU: ++ return "Call Forwarding Unconditional"; ++ case QSIG_DIVERT_REASON_CFB: ++ return "Call Forwarding Busy"; ++ case QSIG_DIVERT_REASON_CFNR: ++ return "Call Forwarding No Reply"; ++ default: ++ return "invalid value"; ++ } ++ } else { ++ switch(diversionreason) { ++ case Q952_DIVERT_REASON_UNKNOWN: ++ return "Unknown"; ++ case Q952_DIVERT_REASON_CFU: ++ return "Call Forwarding Unconditional"; ++ case Q952_DIVERT_REASON_CFB: ++ return "Call Forwarding Busy"; ++ case Q952_DIVERT_REASON_CFNR: ++ return "Call Forwarding No Reply"; ++ case Q952_DIVERT_REASON_CD: ++ return "Call Deflection"; ++ case Q952_DIVERT_REASON_IMMEDIATE: ++ return "Call Deflection Immediate"; ++ default: ++ return "invalid value"; ++ } ++ } ++} ++ ++static const char *callstatus_to_str(int callstatus) ++{ ++ switch (callstatus) { ++ case 0: ++ return "answered"; ++ case 1: ++ return "alerting"; ++ default: ++ return "illegal value"; ++ } ++} ++ ++static const char *enddesignation_to_str(int enddesignation) ++{ ++ switch (enddesignation) { ++ case 0: ++ return "primaryEnd"; ++ case 1: ++ return "secondaryEnd"; ++ default: ++ return "illegal value"; ++ } ++} ++ + int redirectingreason_from_q931(struct pri *pri, int redirectingreason) + { + switch(pri->switchtype) { +@@ -350,8 +474,25 @@ + } + } + +-int asn1_name_decode(void * data, int len, char *namebuf, int buflen) ++static int presentation_to_subscription(struct pri *pri, int presentation) + { ++ /* derive subscription value from presentation value */ ++ ++ switch (presentation & PRES_RESTRICTION) { ++ case PRES_ALLOWED: ++ return QSIG_NOTIFICATION_WITH_DIVERTED_TO_NR; ++ case PRES_RESTRICTED: ++ return QSIG_NOTIFICATION_WITHOUT_DIVERTED_TO_NR; ++ case PRES_UNAVAILABLE: /* Number not available due to interworking */ ++ return QSIG_NOTIFICATION_WITHOUT_DIVERTED_TO_NR; /* ?? QSIG_NO_NOTIFICATION */ ++ default: ++ pri_message(pri, "!! Unknown Q.SIG presentationIndicator 0x%02x\n", presentation); ++ return QSIG_NOTIFICATION_WITHOUT_DIVERTED_TO_NR; ++ } ++} ++ ++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; + +@@ -361,11 +502,13 @@ + } else + datalen = res = comp->len; + +- if (datalen > buflen) { ++ if (datalen > buflen - 1) { + /* Truncate */ + datalen = buflen; + } + memcpy(namebuf, comp->data, datalen); ++ namebuf[datalen] = '\0'; ++ + return res + 2; + } + +@@ -407,42 +550,230 @@ + return res; + } + +-static int rose_number_digits_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value) ++static int rose_namedata_decode(struct pri *pri, unsigned char *data, int len, int implicit, struct nameelements_namedata *value) + { + int i = 0; + struct rose_component *comp = NULL; + unsigned char *vdata = data; +- int datalen = 0; +- int res = 0; ++ int res; + + do { ++ /* NameData */ ++ if (!implicit) { ++ GET_COMPONENT(comp, i, vdata, len); ++ CHECK_COMPONENT(comp, ASN1_OCTETSTRING, "Don't know what to do if NameData is of type 0x%x\n"); ++ ++ data = comp->data; ++ if (comp->len == ASN1_LEN_INDEF) { ++ len = strlen((char *)comp->data); ++ res = len + 2 + 2; ++ } else { ++ len = comp->len; ++ res = len + 2; ++ } ++ } else ++ res = len; ++ ++ if (len > sizeof(value->name)-1) { ++ pri_message(pri, "!! Oversized NameData component (%d)\n", len); ++ return -1; ++ } ++ ++ memcpy(value->name, data, len); ++ value->name[len] = '\0'; ++ ++ return res; ++ } ++ while(0); ++ ++ return -1; ++} ++ ++static int rose_namedata_encode(struct pri *pri, unsigned char *dst, int implicit, char *name) ++{ ++ int size = 0; ++ struct rose_component *comp; ++ int namesize; ++ ++ namesize = strlen(name); ++ if (namesize > 50 ) { ++ pri_message(pri, "!! Encoding of oversized NameData component failed (%d)\n", namesize); ++ return -1; ++ } else if (namesize == 0){ ++ pri_message(pri, "!! Encoding of undersized NameData component failed (%d)\n", namesize); ++ return -1; ++ } ++ ++ if (!implicit) { ++ /* constructor component (0x04,len) */ ++ comp = (struct rose_component *)dst; ++ comp->type = ASN1_OCTETSTRING; ++ comp->len = 2 + namesize; ++ size += 2; ++ dst += 2; ++ } ++ ++ memcpy(dst, name, namesize); ++ size += namesize; ++ ++ return size; ++} ++ ++static int rose_nameset_decode(struct pri *pri, unsigned char *data, int len, int implicit, struct nameelements_nameset *value) ++{ ++ int size; ++ int i = 0; ++ struct rose_component *comp = NULL; ++ unsigned char *vdata = data; ++ int characterset; ++ ++ value->characterset = CHARACTER_SET_ISO8859_1; ++ ++ do { ++ /* NameSet */ ++ if (!implicit) { ++ GET_COMPONENT(comp, i, vdata, len); ++ CHECK_COMPONENT(comp, ASN1_SEQUENCE, "Don't know what to do if NameSet is of type 0x%x\n"); ++ SUB_COMPONENT(comp, i); ++ } ++ ++ /* nameData NameData */ + 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 && comp->len != ASN1_LEN_INDEF) { +- pri_message(pri, "!! Oversized NumberDigits component (%d)\n", comp->len); ++ size = rose_namedata_decode(pri, (u_int8_t *)comp, len, 0, (struct nameelements_namedata *)value); ++ if (size < 0) + return -1; ++ i += size; ++ ++ if (i < len) { ++ /* characterSet CharacterSet OPTIONAL */ ++ GET_COMPONENT(comp, i, vdata, len); ++ CHECK_COMPONENT(comp, ASN1_INTEGER, "Don't know what to do if CharacterSet is of type 0x%x\n"); ++ ASN1_GET_INTEGER(comp, characterset); ++ NEXT_COMPONENT(comp, i); ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " NameSet: Received characterSet=%s(%d)\n", characterset_to_str(characterset), characterset); ++ value->characterset = characterset; + } +- if (comp->len == ASN1_LEN_INDEF) { +- datalen = strlen((char *)comp->data); +- res = datalen + 2; +- } else +- res = datalen = comp->len; +- +- memcpy(value->partyaddress, comp->data, datalen); +- value->partyaddress[datalen] = '\0'; + +- return res + 2; ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " NameSet: '%s', characterSet=%s(%d) i=%d len=%d\n", value->name, characterset_to_str(value->characterset), value->characterset, i, len); ++ ++ return i; + } + while(0); + + return -1; + } + +-static int rose_public_party_number_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value) ++static int rose_name_decode(struct pri *pri, unsigned char *data, int len, struct nameelements_name *value) + { + int i = 0; ++ int size = 0; + struct rose_component *comp = NULL; + unsigned char *vdata = data; ++ ++ value->name[0] = '\0'; ++ value->characterset = CHARACTER_SET_UNKNOWN; ++ value->namepres = -1; ++ ++ do { ++ GET_COMPONENT(comp, i, vdata, len); ++ ++ switch(comp->type) { ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0): /* [0] namePresentationAllowedSimple */ ++ size = rose_namedata_decode(pri, comp->data, comp->len, 1, (struct nameelements_namedata *)value); ++ if (size < 0) ++ return -1; ++ i += (size + 2); ++ value->characterset = CHARACTER_SET_ISO8859_1; ++ value->namepres = 1; ++ break; ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1): /* [1] namePresentationAllowedExtended */ ++ size = rose_nameset_decode(pri, comp->data, comp->len, 1, (struct nameelements_nameset *)value); ++ if (size < 0) ++ return -1; ++ i += (size + 2); ++ value->namepres = 1; ++ break; ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2): /* [2] namePresentationRestrictedSimple */ ++ size = rose_namedata_decode(pri, comp->data, comp->len, 1, (struct nameelements_namedata *)value); ++ if (size < 0) ++ return -1; ++ i += (size + 2); ++ value->characterset = CHARACTER_SET_ISO8859_1; ++ value->namepres = 0; ++ break; ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] namePresentationRestrictedExtended */ ++ size = rose_nameset_decode(pri, comp->data, comp->len, 1, (struct nameelements_nameset *)value); ++ if (size < 0) ++ return -1; ++ i += (size + 2); ++ value->namepres = 0; ++ break; ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_4): /* [4] nameNotAvailable */ ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_7): /* [7] namePresentationRestrictedNull */ ++ i += (comp->len + 2); ++ value->name[0] = '\0'; ++ value->characterset = CHARACTER_SET_UNKNOWN; ++ value->namepres = 0; ++ break; ++ default: ++ pri_message(pri, "!! Unknown Name component received 0x%x\n", comp->type); ++ return -1; ++ } ++ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " Name: '%s' i=%d len=%d\n", value->name, i, len); ++ return i; ++ } ++ while (0); ++ ++ return -1; ++} ++ ++static int rose_number_digits_decode(struct pri *pri, unsigned char *data, int len, int implicit, struct addressingdataelements_presentednumberunscreened *value) ++{ ++ int i = 0; ++ struct rose_component *comp = NULL; ++ unsigned char *vdata = data; ++ int res = 0; ++ ++ do { ++ if (!implicit) { ++ GET_COMPONENT(comp, i, vdata, len); ++ CHECK_COMPONENT(comp, ASN1_NUMERICSTRING, "Don't know what to do with NumberDigits ROSE component type 0x%x\n"); ++ ++ data = comp->data; ++ if (comp->len == ASN1_LEN_INDEF) { ++ len = strlen((char *)comp->data); ++ res = len + 2 + 2; ++ } else { ++ len = comp->len; ++ res = len + 2; ++ } ++ } else ++ res = len; ++ ++ if (len > sizeof(value->partyaddress)-1) { ++ pri_message(pri, "!! Oversized NumberDigits component (%d)\n", len); ++ return -1; ++ } ++ ++ memcpy(value->partyaddress, data, len); ++ value->partyaddress[len] = '\0'; ++ ++ return res; ++ } ++ while(0); ++ ++ return -1; ++} ++ ++static int rose_public_party_number_decode(struct pri *pri, unsigned char *data, int len, int implicit, struct addressingdataelements_presentednumberunscreened *value) ++{ ++ int i = 0; ++ struct rose_component *comp = NULL; ++ unsigned char *vdata = data; + int ton; + int res = 0; + +@@ -450,13 +781,19 @@ + return -1; + + do { ++ if (!implicit) { ++ GET_COMPONENT(comp, i, vdata, len); ++ CHECK_COMPONENT(comp, ASN1_SEQUENCE, "Don't know what to do if PublicPartyNumber is of type 0x%x\n"); ++ SUB_COMPONENT(comp, i); ++ } ++ + 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); + +- res = rose_number_digits_decode(pri, call, &vdata[i], len-i, value); ++ res = rose_number_digits_decode(pri, &vdata[i], len-i, 0, value); + if (res < 0) + return -1; + value->ton = ton; +@@ -467,8 +804,48 @@ + return -1; + } + +-static int rose_private_party_number_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value) ++static int rose_public_party_number_encode(struct pri *pri, unsigned char *dst, int implicit, unsigned char ton, char *num) + { ++ int i = 0, compsp = 0; ++ struct rose_component *comp, *compstk[10]; ++ int numsize; ++ ++ numsize = strlen(num); ++ if (numsize > 20 ) { ++ pri_message(pri, "!! Encoding of oversized PublicPartyNumber component failed (%d)\n", numsize); ++ return -1; ++ } ++ ++ if (!implicit) { ++ /* constructor component (0x30,len) */ ++ ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), dst, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ } else ++ comp = (struct rose_component *)dst; ++ ++ /* publicTypeOfNumber (0x0a,0x01,ton)*/ ++ ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, dst, i, ton); ++ ++ /* publicNumberDigits */ ++ ++ /* tag component NumericString (0x12,len) */ ++ ASN1_ADD_SIMPLE(comp, ASN1_NUMERICSTRING, dst, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* NumericString */ ++ memcpy(comp->data, num, numsize); ++ i += numsize; ++ ++ ASN1_FIXUP(compstk, compsp, dst, i); ++ ++ if (!implicit) ++ ASN1_FIXUP(compstk, compsp, dst, i); ++ ++ return i; ++} ++ ++static int rose_private_party_number_decode(struct pri *pri, unsigned char *data, int len, int implicit, struct addressingdataelements_presentednumberunscreened *value) ++{ + int i = 0; + struct rose_component *comp = NULL; + unsigned char *vdata = data; +@@ -476,18 +853,24 @@ + int res = 0; + + if (len < 2) +- return -1; ++ return -1; + + do { ++ if (!implicit) { ++ GET_COMPONENT(comp, i, vdata, len); ++ CHECK_COMPONENT(comp, ASN1_SEQUENCE, "Don't know what to do if PrivatePartyNumber is of type 0x%x\n"); ++ SUB_COMPONENT(comp, i); ++ } ++ + GET_COMPONENT(comp, i, vdata, len); + CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Don't know what to do with PrivatePartyNumber ROSE component type 0x%x\n"); + ASN1_GET_INTEGER(comp, ton); + NEXT_COMPONENT(comp, i); + ton = typeofnumber_for_q931(pri, ton); + +- res = rose_number_digits_decode(pri, call, &vdata[i], len-i, value); ++ res = rose_number_digits_decode(pri, &vdata[i], len-i, 0, value); + if (res < 0) +- return -1; ++ return -1; + value->ton = ton; + + return res + 3; +@@ -496,7 +879,7 @@ + return -1; + } + +-static int rose_address_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value) ++static int rose_address_decode(struct pri *pri, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value) + { + int i = 0; + struct rose_component *comp = NULL; +@@ -506,65 +889,59 @@ + do { + GET_COMPONENT(comp, i, vdata, len); + ++ /* PartyNumber */ + switch(comp->type) { +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* [0] unknownPartyNumber */ +- res = rose_number_digits_decode(pri, call, comp->data, comp->len, value); ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0): /* [0] unknownPartyNumber, IMPLICIT NumberDigits */ ++ res = rose_number_digits_decode(pri, comp->data, comp->len, 1, value); + if (res < 0) + return -1; + value->npi = PRI_NPI_UNKNOWN; + value->ton = PRI_TON_UNKNOWN; + break; +- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0): /* [0] unknownPartyNumber */ +- res = asn1_copy_string(value->partyaddress, sizeof(value->partyaddress), comp); ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1): /* [1] publicPartyNumber, IMPLICIT PublicPartyNumber */ ++ res = rose_public_party_number_decode(pri, comp->data, comp->len, 1, value); + if (res < 0) + return -1; +- value->npi = PRI_NPI_UNKNOWN; +- value->ton = PRI_TON_UNKNOWN; ++ value->npi = PRI_NPI_E163_E164; + break; +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1): /* [1] publicPartyNumber */ +- res = rose_public_party_number_decode(pri, call, comp->data, comp->len, value); ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_3): /* [3] dataPartyNumber, IMPLICIT NumberDigits */ ++ res = rose_number_digits_decode(pri, comp->data, comp->len, 1, value); + if (res < 0) + return -1; +- value->npi = PRI_NPI_E163_E164; +- break; +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_2): /* [2] nsapEncodedNumber */ +- pri_message(pri, "!! NsapEncodedNumber isn't handled\n"); +- return -1; +- 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(pri, "!! dataPartyNumber isn't handled\n"); + return -1; +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_4): /* [4] telexPartyNumber */ +- res = rose_number_digits_decode(pri, call, comp->data, comp->len, value); ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_4): /* [4] telexPartyNumber, IMPLICIT NumberDigits */ ++ res = rose_number_digits_decode(pri, comp->data, comp->len, 1, value); + if (res < 0) + return -1; + value->npi = PRI_NPI_F69 /* ??? */; + value->ton = PRI_TON_UNKNOWN /* ??? */; + pri_message(pri, "!! telexPartyNumber isn't handled\n"); + return -1; +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_5): /* [5] priavePartyNumber */ +- res = rose_private_party_number_decode(pri, call, comp->data, comp->len, value); ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_5): /* [5] privatePartyNumber, IMPLICIT PrivatePartyNumber */ ++ res = rose_private_party_number_decode(pri, comp->data, comp->len, 1, value); + if (res < 0) +- return -1; ++ return -1; + value->npi = PRI_NPI_PRIVATE; + break; +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_8): /* [8] nationalStandardPartyNumber */ +- res = rose_number_digits_decode(pri, call, comp->data, comp->len, value); ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_8): /* [8] nationalStandardPartyNumber, IMPLICIT NumberDigits */ ++ res = rose_number_digits_decode(pri, comp->data, comp->len, 1, value); + if (res < 0) + return -1; + value->npi = PRI_NPI_NATIONAL; + value->ton = PRI_TON_NATIONAL; + break; + default: +- pri_message(pri, "!! Unknown Party number component received 0x%X\n", comp->type); ++ pri_message(pri, "!! Unknown PartyNumber component received 0x%X\n", comp->type); + return -1; + } + ASN1_FIXUP_LEN(comp, res); + NEXT_COMPONENT(comp, i); +- if(i < len) ++ ++ /* PartySubaddress OPTIONAL */ ++ if (i < len) + pri_message(pri, "!! not all information is handled from Address component\n"); + return res + 2; + } +@@ -573,14 +950,176 @@ + return -1; + } + +-static int rose_presented_number_unscreened_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value) ++static int rose_party_number_encode(struct pri *pri, unsigned char *dst, unsigned char ton, char *num) + { ++ int i = 0, compsp = 0; ++ struct rose_component *comp, *compstk[10]; ++ int numsize, size; ++ ++ numsize = strlen(num); ++ if (numsize > 20 ) { ++ pri_message(pri, "!! Encoding of oversized PartyNumber component failed (%d)\n", numsize); ++ return -1; ++ } ++ ++#if 0 ++ /* tag component unknownPartyNumber (0x80,len) */ ++ ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), dst, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* unknownPartyNumber, implicid NumberDigits */ ++ memcpy(comp->data, num, numsize); ++ i += numsize; ++ ++ ASN1_FIXUP(compstk, compsp, dst, i); ++#endif ++ ++ /* tag component publicPartyNumber (0xa1,len) */ ++ ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), dst, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* publicPartyNumber, implicid PublicPartyNumber */ ++ size = rose_public_party_number_encode(pri, comp->data, 1, ton, num); ++ if (size < 0) ++ return -1; ++ i += size; ++ ++ ASN1_FIXUP(compstk, compsp, dst, i); ++ ++ return i; ++} ++ ++static int rose_party_number_decode(struct pri *pri, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value) ++{ + int i = 0; + int size = 0; + struct rose_component *comp = NULL; + unsigned char *vdata = data; + ++ do { ++ GET_COMPONENT(comp, i, vdata, len); ++ ++ switch(comp->type) { ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0): /* [0] IMPLICIT NumberDigits -- default: unknownPartyNumber */ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " PartyNumber: UnknownPartyNumber len=%d\n", len); ++ size = rose_number_digits_decode(pri, comp->data, comp->len, 1, value); ++ if (size < 0) ++ return -1; ++ value->npi = PRI_NPI_UNKNOWN; ++ value->ton = PRI_TON_UNKNOWN; ++ break; ++ ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1): /* [1] IMPLICIT PublicPartyNumber */ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " PartyNumber: PublicPartyNumber len=%d\n", len); ++ size = rose_public_party_number_decode(pri, comp->data, comp->len, 1, value); ++ if (size < 0) ++ return -1; ++ value->npi = PRI_NPI_E163_E164; ++ break; ++ ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_3): /* [3] IMPLICIT NumberDigits -- not used: dataPartyNumber */ ++ pri_message(pri, "!! PartyNumber: dataPartyNumber is reserved!\n"); ++ size = rose_number_digits_decode(pri, comp->data, comp->len, 1, value); ++ if (size < 0) ++ return -1; ++ value->npi = PRI_NPI_X121 /* ??? */; ++ value->ton = PRI_TON_UNKNOWN /* ??? */; ++ break; ++ ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_4): /* [4] IMPLICIT NumberDigits -- not used: telexPartyNumber */ ++ pri_message(pri, "!! PartyNumber: telexPartyNumber is reserved!\n"); ++ size = rose_number_digits_decode(pri, comp->data, comp->len, 1, value); ++ if (size < 0) ++ return -1; ++ value->npi = PRI_NPI_F69 /* ??? */; ++ value->ton = PRI_TON_UNKNOWN /* ??? */; ++ break; ++ ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_5): /* [5] IMPLICIT PrivatePartyNumber */ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " PartyNumber: PrivatePartyNumber len=%d\n", len); ++ size = rose_private_party_number_decode(pri, comp->data, comp->len, 1, value); ++ if (size < 0) ++ return -1; ++ value->npi = PRI_NPI_PRIVATE; ++ break; ++ ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_8): /* [8] IMPLICIT NumberDigits -- not used: nationalStandatdPartyNumber */ ++ pri_message(pri, "!! PartyNumber: nationalStandardPartyNumber is reserved!\n"); ++ size = rose_number_digits_decode(pri, comp->data, comp->len, 1, value); ++ if (size < 0) ++ return -1; ++ value->npi = PRI_NPI_NATIONAL; ++ value->ton = PRI_TON_NATIONAL; ++ break; ++ ++ default: ++ pri_message(pri, "Invalid PartyNumber component 0x%X\n", comp->type); ++ return -1; ++ } ++ ASN1_FIXUP_LEN(comp, size); ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " PartyNumber: '%s' size=%d len=%d\n", value->partyaddress, size, len); ++ return size; ++ } ++ while (0); ++ ++ return -1; ++} ++ ++static int rose_presented_number_unscreened_encode(struct pri *pri, unsigned char *dst, unsigned char presentation, unsigned char ton, char *num) ++{ ++ int i = 0, compsp = 0; ++ struct rose_component *comp, *compstk[10]; ++ int numsize, size; ++ ++ numsize = strlen(num); ++ if (numsize > 20 ) { ++ pri_message(pri, "!! Encoding of oversized PresentedNumberUnscreened component failed (%d)\n", numsize); ++ return -1; ++ } ++ ++ switch (presentation & PRES_RESTRICTION) { ++ case PRES_ALLOWED: ++ /* tag component [0] presentationAllowedAddress (0xa0,len) */ ++ ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0), dst, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* PartyNumber */ ++ size = rose_party_number_encode(pri, comp->data, ton, num); ++ if (size < 0) ++ return -1; ++ i += size; ++ ASN1_FIXUP(compstk, compsp, dst, i); ++ break; ++ case PRES_RESTRICTED: ++ /* tag component [1] presentationRestricted (0x81,len) */ ++ ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), dst, i); ++ break; ++ case PRES_UNAVAILABLE: ++ /* tag component [2] numberNotAvailableDueToInterworking (0x82,len) */ ++ ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), dst, i); ++ /* ASN1_FIXUP(compstk, compsp, dst, i); */ ++ break; ++ default: ++ pri_message(pri, "!! Undefined presentation value for PresentedNumberUnscreened: 0x%x\n", presentation); ++ return -1; ++ } ++ ++ return i; ++} ++ ++static int rose_presented_number_unscreened_decode(struct pri *pri, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value) ++{ ++ int i = 0; ++ int size = 0; ++ struct rose_component *comp = NULL; ++ unsigned char *vdata = data; ++ + /* Fill in default values */ ++ value->partyaddress[0] = '\0'; + value->ton = PRI_TON_UNKNOWN; + value->npi = PRI_NPI_E163_E164; + value->pres = -1; /* Data is not available */ +@@ -591,7 +1130,7 @@ + switch(comp->type) { + case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* [0] presentationAllowedNumber */ + value->pres = PRES_ALLOWED_USER_NUMBER_NOT_SCREENED; +- size = rose_address_decode(pri, call, comp->data, comp->len, value); ++ size = rose_address_decode(pri, comp->data, comp->len, value); + ASN1_FIXUP_LEN(comp, size); + return size + 2; + case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1): /* [1] IMPLICIT presentationRestricted */ +@@ -610,7 +1149,7 @@ + return 2; + case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] presentationRestrictedNumber */ + value->pres = PRES_PROHIB_USER_NUMBER_NOT_SCREENED; +- size = rose_address_decode(pri, call, comp->data, comp->len, value) + 2; ++ size = rose_address_decode(pri, comp->data, comp->len, value) + 2; + ASN1_FIXUP_LEN(comp, size); + return size + 2; + default: +@@ -623,17 +1162,482 @@ + return -1; + } + ++static int rose_number_screened_encode(struct pri *pri, unsigned char *dst, int implicit, unsigned char ton, unsigned char screenind, char *num) ++{ ++ int i = 0, compsp = 0; ++ struct rose_component *comp, *compstk[10]; ++ int numsize, size; ++ ++ numsize = strlen(num); ++ if (numsize > 20 ) { ++ pri_message(pri, "!! Encoding of oversized NumberScreened component failed (%d)\n", numsize); ++ return -1; ++ } ++ ++ if (!implicit) { ++ /* constructor component (0x30,len) */ ++ ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), dst, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ } else ++ comp = (struct rose_component *)dst; ++ ++ /* PartyNumber */ ++ size = rose_party_number_encode(pri, (u_int8_t *)comp, ton, num); ++ if (size < 0) ++ return -1; ++ i += size; ++ ++ /* ScreeningIndicator (0x0a,0x01,screenind) */ ++ ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, dst, i, screenind); ++ ++ if (!implicit) ++ ASN1_FIXUP(compstk, compsp, dst, i); ++ ++ return i; ++} ++ ++static int rose_number_screened_decode(struct pri *pri, unsigned char *data, int len, struct addressingdataelements_presentednumberscreened *value) ++{ ++ int i = 0; ++ int size = 0; ++ struct rose_component *comp = NULL; ++ unsigned char *vdata = data; ++ ++ int scrind = -1; ++ ++ do { ++ /* Party Number */ ++ GET_COMPONENT(comp, i, vdata, len); ++ size = rose_party_number_decode(pri, (u_int8_t *)comp, comp->len + 2, (struct addressingdataelements_presentednumberunscreened*) value); ++ if (size < 0) ++ return -1; ++ comp->len = size; ++ NEXT_COMPONENT(comp, i); ++ ++ /* Screening Indicator */ ++ GET_COMPONENT(comp, i, vdata, len); ++ CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Don't know what to do with NumberScreened ROSE component type 0x%x\n"); ++ ASN1_GET_INTEGER(comp, scrind); ++ // Todo: scrind = screeningindicator_for_q931(pri, scrind); ++ NEXT_COMPONENT(comp, i); ++ ++ value->scrind = scrind; ++ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " NumberScreened: '%s' ScreeningIndicator=%d i=%d len=%d\n", value->partyaddress, scrind, i, len); ++ ++ return i-2; // We do not have a sequence header here. ++ } ++ while (0); ++ ++ return -1; ++} ++ ++static int rose_presented_number_screened_decode(struct pri *pri, unsigned char *data, int len, struct addressingdataelements_presentednumberscreened *value) ++{ ++ int i = 0; ++ int size = 0; ++ struct rose_component *comp = NULL; ++ unsigned char *vdata = data; ++ ++ /* Fill in default values */ ++ value->partyaddress[0] = '\0'; ++ value->ton = PRI_TON_UNKNOWN; ++ value->npi = PRI_NPI_UNKNOWN; ++ value->pres = -1; /* Data is not available */ ++ value->scrind = 0; ++ ++ do { ++ GET_COMPONENT(comp, i, vdata, len); ++ ++ switch(comp->type) { ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* [0] IMPLICIT presentationAllowedNumber */ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " PresentedNumberScreened: presentationAllowedNumber comp->len=%d\n", comp->len); ++ value->pres = PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN; ++ size = rose_number_screened_decode(pri, comp->data, comp->len, value); ++ if (size < 0) ++ return -1; ++ ASN1_FIXUP_LEN(comp, size); ++ return size + 2; ++ ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1): /* [1] IMPLICIT presentationRestricted */ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " PresentedNumberScreened: presentationRestricted comp->len=%d\n", comp->len); ++ if (comp->len != 0) { /* must be NULL */ ++ pri_error(pri, "!! Invalid PresentationRestricted component received (len != 0)\n"); ++ return -1; ++ } ++ value->pres = PRES_PROHIB_USER_NUMBER_PASSED_SCREEN; ++ return 2; ++ ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2): /* [2] IMPLICIT numberNotAvailableDueToInterworking */ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " PresentedNumberScreened: NumberNotAvailableDueToInterworking comp->len=%d\n", comp->len); ++ if (comp->len != 0) { /* must be NULL */ ++ pri_error(pri, "!! Invalid NumberNotAvailableDueToInterworking component received (len != 0)\n"); ++ return -1; ++ } ++ value->pres = PRES_NUMBER_NOT_AVAILABLE; ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " PresentedNumberScreened: numberNotAvailableDueToInterworking Type=0x%X i=%d len=%d size=%d\n", comp->type, i, len); ++ return 2; ++ ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] IMPLICIT presentationRestrictedNumber */ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " PresentedNumberScreened: presentationRestrictedNumber comp->len=%d\n", comp->len); ++ value->pres = PRES_PROHIB_USER_NUMBER_PASSED_SCREEN; ++ size = rose_number_screened_decode(pri, comp->data, comp->len, value); ++ if (size < 0) ++ return -1; ++ ASN1_FIXUP_LEN(comp, size); ++ return size + 2; ++ ++ default: ++ pri_message(pri, "Invalid PresentedNumberScreened component 0x%X\n", comp->type); ++ } ++ return -1; ++ } ++ while (0); ++ ++ return -1; ++} ++ ++static int rose_partysubaddress_decode(struct pri *pri, unsigned char *data, int len, struct addressingdataelements_partysubaddress *value) ++{ ++ int i = 0; ++ int size = 0; ++ struct rose_component *comp = NULL; ++ unsigned char *vdata = data; ++ ++ int odd_count_indicator = -1; ++ value->partysubaddress[0] = '\0'; ++ ++ do { ++ GET_COMPONENT(comp, i, vdata, len); ++ ++ switch(comp->type) { ++ case (ASN1_CONSTRUCTOR | ASN1_SEQUENCE): /* UserSpecifiedSubaddress */ ++ /* SubaddressInformation */ ++ SUB_COMPONENT(comp, i); ++ GET_COMPONENT(comp, i, vdata, len); ++ CHECK_COMPONENT(comp, ASN1_OCTETSTRING, "Don't know what to do if SubaddressInformation is of type 0x%x\n"); ++ size = asn1_name_decode(comp->data, comp->len, value->partysubaddress, sizeof(value->partysubaddress)); ++ if (size < 0) ++ return -1; ++ i += size; ++ ++ /* oddCountIndicator BOOLEAN OPTIONAL */ ++ if (i < len) { ++ GET_COMPONENT(comp, i, vdata, len); ++ CHECK_COMPONENT(comp, ASN1_BOOLEAN, "Don't know what to do if SubaddressInformation is of type 0x%x\n"); ++ ++ ASN1_GET_INTEGER(comp, odd_count_indicator); ++ NEXT_COMPONENT(comp, i); ++ } ++ case (ASN1_OCTETSTRING): /* NSAPSubaddress */ ++ size = asn1_name_decode((u_int8_t *)comp, comp->len + 2, value->partysubaddress, sizeof(value->partysubaddress)); ++ if (size < 0) ++ return -1; ++ i += size; ++ break; ++ default: ++ pri_message(pri, "Invalid PartySubaddress component 0x%X\n", comp->type); ++ return -1; ++ } ++ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " PartySubaddress: '%s', oddCountIndicator=%d, i=%d len=%d\n", value->partysubaddress, odd_count_indicator, i, len); ++ ++ return i; ++ } ++ while (0); ++ ++ return -1; ++} ++ ++static int rose_address_screened_decode(struct pri *pri, unsigned char *data, int len, struct addressingdataelements_addressscreened *value) ++{ ++ int i = 0; ++ int size = 0; ++ struct rose_component *comp = NULL; ++ unsigned char *vdata = data; ++ ++ int scrind; ++ value->partysubaddress[0] = '\0'; ++ ++ /* SEQUENCE AddressScreened */ ++ do { ++ /* PartyNumber */ ++ GET_COMPONENT(comp, i, vdata, len); ++ size = rose_party_number_decode(pri, (u_int8_t *)comp, comp->len + 2, (struct addressingdataelements_presentednumberunscreened *)value); ++ if (size < 0) ++ return -1; ++ comp->len = size; ++ NEXT_COMPONENT(comp, i); ++ ++ /* ScreeningIndicator */ ++ GET_COMPONENT(comp, i, vdata, len); ++ CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Don't know what to do with AddressScreened ROSE component type 0x%x\n"); ++ ASN1_GET_INTEGER(comp, scrind); ++ NEXT_COMPONENT(comp, i); ++ ++ if (i < len) { ++ /* PartySubaddress OPTIONAL */ ++ GET_COMPONENT(comp, i, vdata, len); ++ size = rose_partysubaddress_decode(pri, (u_int8_t *)comp, comp->len + 2, (struct addressingdataelements_partysubaddress *)value); ++ if (size < 0) ++ return -1; ++ i += size; ++ } ++ ++ value->scrind = scrind; ++ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " AddressScreened: '%s' ScreeningIndicator=%d i=%d len=%d\n", value->partyaddress, scrind, i, len); ++ ++ return i-2; ++ } ++ while (0); ++ ++ return -1; ++} ++ ++static int rose_presented_address_screened_decode(struct pri *pri, unsigned char *data, int len, struct addressingdataelements_presentedaddressscreened *value) ++{ ++ int i = 0; ++ int size = 0; ++ struct rose_component *comp = NULL; ++ unsigned char *vdata = data; ++ ++ /* Fill in default values */ ++ value->partyaddress[0] = '\0'; ++ value->partysubaddress[0] = '\0'; ++ value->npi = PRI_NPI_UNKNOWN; ++ value->ton = PRI_TON_UNKNOWN; ++ value->pres = -1; /* Data is not available */ ++ value->scrind = 0; ++ ++ do { ++ GET_COMPONENT(comp, i, vdata, len); ++ ++ switch(comp->type) { ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* [0] IMPLICIT presentationAllowedAddress */ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " PresentedAddressScreened: presentationAllowedAddress comp->len=%d\n", comp->len); ++ value->pres = PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN; ++ size = rose_address_screened_decode(pri, comp->data, comp->len, (struct addressingdataelements_addressscreened *)value); ++ if (size < 0) ++ return -1; ++ ASN1_FIXUP_LEN(comp, size); ++ return size + 2; ++ ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1): /* [1] IMPLICIT presentationRestricted */ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " PresentedAddressScreened: presentationRestricted comp->len=%d\n", comp->len); ++ if (comp->len != 0) { /* must be NULL */ ++ pri_error(pri, "!! Invalid PresentationRestricted component received (len != 0)\n"); ++ return -1; ++ } ++ value->pres = PRES_PROHIB_USER_NUMBER_PASSED_SCREEN; ++ return 2; ++ ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2): /* [2] IMPLICIT numberNotAvailableDueToInterworking */ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " PresentedAddressScreened: NumberNotAvailableDueToInterworking comp->len=%d\n", comp->len); ++ if (comp->len != 0) { /* must be NULL */ ++ pri_error(pri, "!! Invalid NumberNotAvailableDueToInterworking component received (len != 0)\n"); ++ return -1; ++ } ++ value->pres = PRES_NUMBER_NOT_AVAILABLE; ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " PresentedAddressScreened: numberNotAvailableDueToInterworking Type=0x%X i=%d len=%d size=%d\n", comp->type, i, len); ++ return 2; ++ ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] IMPLICIT presentationRestrictedAddress */ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " PresentedAddressScreened: presentationRestrictedAddress comp->len=%d\n", comp->len); ++ value->pres = PRES_PROHIB_USER_NUMBER_PASSED_SCREEN; ++ size = rose_address_screened_decode(pri, comp->data, comp->len, (struct addressingdataelements_addressscreened *)value); ++ if (size < 0) ++ return -1; ++ ASN1_FIXUP_LEN(comp, size); ++ return size + 2; ++ ++ default: ++ pri_message(pri, "Invalid PresentedAddressScreened component 0x%X\n", comp->type); ++ } ++ return -1; ++ } ++ while (0); ++ ++ return -1; ++} ++ ++static int rose_diverting_leg_information1_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len) ++{ ++ int i = 0; ++ struct addressingdataelements_presentednumberunscreened nominatednr; ++ int diversion_reason; ++ int subscription_option; ++ struct rose_component *comp = NULL; ++ unsigned char *vdata = sequence->data; ++ int size = 0; ++ memset(&nominatednr, 0, sizeof(nominatednr)); ++ ++ /* Data checks */ ++ if (sequence->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */ ++ pri_message(pri, "Invalid DivertingLegInformation1Type argument\n"); ++ return -1; ++ } ++ ++ if (sequence->len == ASN1_LEN_INDEF) { ++ len -= 4; /* For the 2 extra characters at the end ++ and two characters of header */ ++ } else ++ len -= 2; ++ ++ do { ++ /* diversionReason DiversionReason */ ++ GET_COMPONENT(comp, i, vdata, len); ++ CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Invalid diversionReason type 0x%X of ROSE divertingLegInformation1 component received\n"); ++ ASN1_GET_INTEGER(comp, diversion_reason); ++ NEXT_COMPONENT(comp, i); ++ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " Received diversionReason: %s(%d)\n", diversionreason_to_str(pri, diversion_reason), diversion_reason); ++ ++ diversion_reason = redirectingreason_for_q931(pri, diversion_reason); ++ ++ /* subscriptionOption SubscriptionOption */ ++ GET_COMPONENT(comp, i, vdata, len); ++ CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Invalid subscriptionOption type 0x%X of ROSE divertingLegInformation1 component received\n"); ++ ASN1_GET_INTEGER(comp, subscription_option); ++ NEXT_COMPONENT(comp, i); ++ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " Received subscriptionOption: %d\n", subscription_option); ++ ++ /* nominatedNr PartyNumber */ ++ GET_COMPONENT(comp, i, vdata, len); ++ size = rose_party_number_decode(pri, (u_int8_t *)comp, comp->len + 2, &nominatednr); ++ if (size < 0) ++ return -1; ++ ++ if (pri->debug & PRI_DEBUG_APDU) { ++ pri_message(pri, " Received nominatedNr '%s'\n", nominatednr.partyaddress); ++ pri_message(pri, " ton = %d, npi = %d\n\n", nominatednr.ton, nominatednr.npi); ++ } ++ ++ call->divleginfo1activeflag = 1; ++ if (subscription_option == QSIG_NOTIFICATION_WITH_DIVERTED_TO_NR) { ++ libpri_copy_string(call->divertedtonum, nominatednr.partyaddress, sizeof(call->divertedtonum)); ++ } else { ++ call->divertedtonum[0] = '\0'; ++ } ++ call->divertedtopres = (subscription_option == QSIG_NOTIFICATION_WITH_DIVERTED_TO_NR) ? PRES_ALLOWED_USER_NUMBER_NOT_SCREENED : PRES_PROHIB_USER_NUMBER_NOT_SCREENED; ++ call->divertedtoplan = ((nominatednr.ton & 0x07) << 4) | (nominatednr.npi & 0x0f); ++ call->divertedtoreason = diversion_reason; ++ call->divertedtocount++; ++ ++ return 0; ++ } ++ while (0); ++ ++ return -1; ++} ++ ++int rose_diverting_leg_information1_encode(struct pri *pri, q931_call *call) ++{ ++ int i = 0, compsp = 0; ++ struct rose_component *comp, *compstk[10]; ++ unsigned char buffer[256]; ++ int size; ++ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " Encode divertingLegInformation1\n"); ++ ++ /* Protocol Profile = 0x1f (Networking Extensions) (0x9f) */ ++ buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS); ++ ++ /* Network Facility Extension */ ++ if (pri->switchtype == PRI_SWITCH_QSIG) { ++ /* tag component NetworkFacilityExtension (0xaa, len ) */ ++ ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* sourceEntity (0x80,0x01,0x00) */ ++ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0); /* endPINX(0) */ ++ ++ /* destinationEntity (0x82,0x01,0x00) */ ++ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0); /* endPINX(0) */ ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++ } ++ ++ /* Network Protocol Profile */ ++ /* - not included - */ ++ ++ /* Interpretation APDU (0x8b,0x01,0x00) */ ++ ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0); /* discardAnyUnrecognisedInvokePdu(0) */ ++ ++ /* Service APDU(s): */ ++ ++ /* ROSE InvokePDU (0xa1,len) */ ++ ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* ROSE InvokeID (0x02,0x01,invokeid) */ ++ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri)); ++ ++ /* ROSE operationId (0x02,0x01,0x14)*/ ++ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, ROSE_DIVERTING_LEG_INFORMATION1); ++ ++ /* constructor component (0x30,len) */ ++ ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* diversionReason (0x0a,0x01,diversionreason) */ ++ ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, redirectingreason_from_q931(pri, call->divertedtoreason)); ++ ++ /* subscriptionOption (0x0a,0x01,subscriptionoption) */ ++ ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, presentation_to_subscription(pri, call->divertedtopres)); ++ ++ /* nominatedNr */ ++ ++ /* tag component publicPartyNumber (0xa1,len) */ ++ ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* publicPartyNumber, implicid PublicPartyNumber */ ++ size = rose_public_party_number_encode(pri, &buffer[i], 1, (call->divertedtoplan & 0x70) >> 4, call->divertedtonum); ++ if (size < 0) ++ return -1; ++ i += size; ++ ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++ ++ if (pri_call_apdu_queue(call, Q931_FACILITY, buffer, i, NULL, NULL)) ++ return -1; ++ ++ return 0; ++} ++ + static int rose_diverting_leg_information2_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len) + { + int i = 0; ++ struct rose_component *comp = NULL; ++ unsigned char *vdata = sequence->data; ++ int size = 0; ++ + int diversion_counter; + int diversion_reason; +- char origcalledname[50] = "", redirectingname[50] = ""; ++ int original_diversion_reason = QSIG_DIVERT_REASON_UNKNOWN; ++ struct nameelements_name redirectingname = { "", CHARACTER_SET_UNKNOWN, 0 }; ++ struct nameelements_name origcalledname = { "", CHARACTER_SET_UNKNOWN, 0 };; + struct addressingdataelements_presentednumberunscreened divertingnr; +- struct addressingdataelements_presentednumberunscreened originalcallednr; +- struct rose_component *comp = NULL; +- unsigned char *vdata = sequence->data; +- int res = 0; ++ struct addressingdataelements_presentednumberunscreened originalcallednr; + memset(&divertingnr, 0, sizeof(divertingnr)); + memset(&originalcallednr, 0, sizeof(originalcallednr)); + +@@ -644,249 +1648,429 @@ + } + + if (sequence->len == ASN1_LEN_INDEF) { +- len -= 4; /* For the 2 extra characters at the end +- * and two characters of header */ ++ len -= 4; /* For the 2 extra characters at the end ++ and two characters of header */ + } else + len -= 2; + + do { +- /* diversionCounter stuff */ ++ /* diversionCounter */ + 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"); ++ CHECK_COMPONENT(comp, ASN1_INTEGER, "Don't know what to do if diversionCounter is of type 0x%x\n"); + ASN1_GET_INTEGER(comp, diversion_counter); + NEXT_COMPONENT(comp, i); + +- /* diversionReason stuff */ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " Received diversionCounter: %d\n", diversion_counter); ++ ++ /* diversionReason DiversionReason */ + 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); + ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " Received diversionReason: %s(%d)\n", diversionreason_to_str(pri, diversion_reason), diversion_reason); ++ + diversion_reason = redirectingreason_for_q931(pri, diversion_reason); +- +- if(pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " Redirection reason: %d, total diversions: %d\n", diversion_reason, diversion_counter); +- pri_message(NULL, "Length of message is %d\n", len); + +- for(; i < len; NEXT_COMPONENT(comp, i)) { ++ /* Type SEQUENCE specifies an ordered list of component types. * ++ * We decode all components but for simplicity we don't check the order. */ ++ while (i < len) { + GET_COMPONENT(comp, i, vdata, len); ++ + switch(comp->type) { + case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0): +- call->origredirectingreason = redirectingreason_for_q931(pri, comp->data[0]); ++ /* originalDiversionReason */ ++ ASN1_GET_INTEGER(comp, original_diversion_reason); ++ NEXT_COMPONENT(comp,i); + if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " Received reason for original redirection %d\n", call->origredirectingreason); ++ pri_message(pri, " Received originalDiversionReason: %s(%d)\n", diversionreason_to_str(pri, original_diversion_reason), original_diversion_reason); ++ original_diversion_reason = redirectingreason_for_q931(pri, original_diversion_reason); + break; + case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1): +- res = rose_presented_number_unscreened_decode(pri, call, comp->data, comp->len, &divertingnr); +- /* TODO: Fix indefinite length form hacks */ +- ASN1_FIXUP_LEN(comp, res); +- comp->len = res; +- if (res < 0) ++ /* divertingNr */ ++ size = rose_presented_number_unscreened_decode(pri, comp->data, comp->len, &divertingnr); ++ if (size < 0) + return -1; ++ ASN1_FIXUP_LEN(comp, size); ++ comp->len = size; ++ NEXT_COMPONENT(comp,i); + if (pri->debug & PRI_DEBUG_APDU) { + pri_message(pri, " Received divertingNr '%s'\n", divertingnr.partyaddress); + pri_message(pri, " ton = %d, pres = %d, npi = %d\n", divertingnr.ton, divertingnr.pres, divertingnr.npi); + } + break; + case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_2): +- res = rose_presented_number_unscreened_decode(pri, call, comp->data, comp->len, &originalcallednr); +- if (res < 0) ++ /* originalCalledNr */ ++ size = rose_presented_number_unscreened_decode(pri, comp->data, comp->len, &originalcallednr); ++ if (size < 0) + return -1; +- ASN1_FIXUP_LEN(comp, res); +- comp->len = res; ++ ASN1_FIXUP_LEN(comp, size); ++ comp->len = size; ++ NEXT_COMPONENT(comp,i); + if (pri->debug & PRI_DEBUG_APDU) { +- pri_message(pri, " Received originalcallednr '%s'\n", originalcallednr.partyaddress); ++ pri_message(pri, " Received originalCalledNr '%s'\n", originalcallednr.partyaddress); + pri_message(pri, " ton = %d, pres = %d, npi = %d\n", originalcallednr.ton, originalcallednr.pres, originalcallednr.npi); + } + break; + case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): +- res = asn1_name_decode(comp->data, comp->len, redirectingname, sizeof(redirectingname)); +- if (res < 0) ++ /* redirectingName */ ++ size = rose_name_decode(pri, comp->data, comp->len, &redirectingname); ++ if (size < 0) + return -1; +- ASN1_FIXUP_LEN(comp, res); +- comp->len = res; ++ i += (size + 2); + if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " Received RedirectingName '%s'\n", redirectingname); ++ pri_message(pri, " Received RedirectingName '%s', namepres %s(%d), characterset %s(%d)\n", ++ redirectingname.name, namepres_to_str(redirectingname.namepres), redirectingname.namepres, ++ characterset_to_str(redirectingname.characterset), redirectingname.characterset); + break; + case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_4): +- res = asn1_name_decode(comp->data, comp->len, origcalledname, sizeof(origcalledname)); +- if (res < 0) ++ /* originalCalledName */ ++ size = rose_name_decode(pri, comp->data, comp->len, &origcalledname); ++ if (size < 0) + return -1; +- ASN1_FIXUP_LEN(comp, res); +- comp->len = res; ++ i += (size + 2); + if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " Received Originally Called Name '%s'\n", origcalledname); ++ pri_message(pri, " Received OriginalCalledName '%s', namepres %s(%d), characterset %s(%d)\n", ++ origcalledname.name, namepres_to_str(origcalledname.namepres), origcalledname.namepres, ++ characterset_to_str(origcalledname.characterset), origcalledname.characterset); + break; +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_5): +- pri_message(pri, "!! Ignoring DivertingLegInformation2 component 0x%X\n", comp->type); ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_5): /* [5] IMPLICIT Extension */ ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_6): /* [6] IMPLICIT SEQUENCE OF Extension */ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "!! Ignoring DivertingLegInformation2 component 0x%X\n", comp->type); ++ NEXT_COMPONENT(comp, i); + break; + default: +- if (comp->type == 0 && comp->len == 0) { +- break; /* Found termination characters */ +- } +- pri_message(pri, "!! Invalid DivertingLegInformation2 component received 0x%X\n", comp->type); ++ pri_message(pri, "!! Invalid DivertingLegInformation2 component received 0x%X\n", comp->type); + return -1; + } + } + + if (divertingnr.pres >= 0) { +- call->redirectingplan = divertingnr.npi; ++ call->redirectingplan = ((divertingnr.ton & 0x07) << 4) | (divertingnr.npi & 0x0f); + call->redirectingpres = divertingnr.pres; + call->redirectingreason = diversion_reason; + libpri_copy_string(call->redirectingnum, divertingnr.partyaddress, sizeof(call->redirectingnum)); +- pri_message(pri, " Received redirectingnum '%s' (%d)\n", call->redirectingnum, (int)call->redirectingnum[0]); + } + if (originalcallednr.pres >= 0) { +- call->origcalledplan = originalcallednr.npi; ++ call->origcalledplan = ((originalcallednr.ton & 0x07) << 4) | (originalcallednr.npi & 0x0f); + call->origcalledpres = originalcallednr.pres; + libpri_copy_string(call->origcallednum, originalcallednr.partyaddress, sizeof(call->origcallednum)); +- pri_message(pri, " Received origcallednum '%s' (%d)\n", call->origcallednum, (int)call->origcallednum[0]); + } +- libpri_copy_string(call->redirectingname, redirectingname, sizeof(call->redirectingname)); +- libpri_copy_string(call->origcalledname, origcalledname, sizeof(call->origcalledname)); ++ ++ if (redirectingname.namepres != 0) { ++ libpri_copy_string(call->redirectingname, redirectingname.name, sizeof(call->redirectingname)); ++ } else { ++ call->redirectingname[0] = '\0'; ++ } ++ ++ if (origcalledname.namepres != 0) { ++ libpri_copy_string(call->origcalledname, origcalledname.name, sizeof(call->origcalledname)); ++ } else { ++ call->origcalledname[0] = '\0'; ++ } ++ ++ call->origredirectingreason = original_diversion_reason; ++ call->redirectingcount = diversion_counter; ++ + return 0; + } + while (0); + + return -1; + } +- ++ + static int rose_diverting_leg_information2_encode(struct pri *pri, q931_call *call) + { +- int i = 0, j, compsp = 0; ++ int i = 0, compsp = 0; + struct rose_component *comp, *compstk[10]; + unsigned char buffer[256]; +- int len = 253; +- +-#if 0 /* This is not required by specifications */ +- if (!strlen(call->callername)) { +- return -1; ++ int size; ++ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " Encode divertingLegInformation2\n"); ++ ++ /* Protocol Profile = 0x1f (Networking Extensions) (0x9f) */ ++ buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS); ++ ++ /* Network Facility Extension */ ++ if (pri->switchtype == PRI_SWITCH_QSIG) { ++ /* tag component NetworkFacilityExtension (0xaa, len ) */ ++ ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* sourceEntity (0x80,0x01,0x00) */ ++ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0); /* endPINX(0) */ ++ ++ /* destinationEntity (0x82,0x01,0x00) */ ++ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0); /* endPINX(0) */ ++ ASN1_FIXUP(compstk, compsp, buffer, i); + } +-#endif + +- buffer[i] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS); +- i++; +- /* Interpretation component */ +- ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0x00 /* Discard unrecognized invokes */); +- ++ /* Network Protocol Profile */ ++ /* - not included - */ ++ ++ /* Interpretation APDU (0x8b,0x01,0x00) */ ++ ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0); /* discardAnyUnrecognisedInvokePdu(0) */ ++ ++ /* Service APDU(s): */ ++ ++ /* ROSE InvokePDU (0xa1,len) */ + ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i); +- + ASN1_PUSH(compstk, compsp, comp); +- /* Invoke component contents */ +- /* Invoke ID */ ++ ++ /* ROSE InvokeID (0x02,0x01,invokeid) */ + ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri)); +- /* Operation Tag */ +- +- /* ROSE operationId component */ ++ ++ /* ROSE operationId (0x02,0x01,0x15)*/ + ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, ROSE_DIVERTING_LEG_INFORMATION2); + +- /* ROSE ARGUMENT component */ ++ /* constructor component (0x30,len) */ + 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 */ ++ ++ /* diversionCounter always is 1 because other isn't available in the current design */ ++ /* diversionCounter (0x02,0x01,0x01) */ + ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, 1); +- +- /* ROSE DivertingLegInformation2.diversionReason component */ ++ ++ /* diversionReason (0x0a,0x01,redirectingreason) */ + ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, redirectingreason_from_q931(pri, call->redirectingreason)); +- +- /* ROSE DivertingLegInformation2.divertingNr component */ ++ ++ /* originalDiversionReason */ ++ /* - not included - */ ++ ++ /* divertingNr */ ++ ++ /* tag component divertingNr (0xa1,len) */ + ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), 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, (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, (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)); +- if (j < 0) +- return -1; +- +- i += j; +- ASN1_FIXUP(compstk, compsp, buffer, i); +- ASN1_FIXUP(compstk, compsp, buffer, i); +- break; +- } +- /* fall through */ +- case PRES_PROHIB_USER_NUMBER_PASSED_SCREEN: +- case PRES_PROHIB_USER_NUMBER_NOT_SCREENED: +- 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, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), buffer, i); +- break; +- default: +- pri_message(pri, "!! Undefined presentation value for redirecting number: %d\n", call->redirectingpres); +- case PRES_NUMBER_NOT_AVAILABLE: +- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i); +- break; +- } ++ ++ size = rose_presented_number_unscreened_encode(pri, &buffer[i], call->redirectingpres, typeofnumber_from_q931(pri, (call->redirectingplan & 0x70) >> 4), call->redirectingnum); ++ if (size < 0) ++ return -1; ++ i += size; + ASN1_FIXUP(compstk, compsp, buffer, i); + +- /* ROSE DivertingLegInformation2.originalCalledNr component */ +- /* This information isn't supported by current design - duplicate divertingNr */ ++ /* originalCalledNr */ ++ /* - not included - */ ++ ++#if 0 ++ /* The originalCalledNr is unknown here. Its the same as divertingNr if the call * ++ * is diverted only once but we don't know if its diverted one ore more times. */ ++ ++ /* originalCalledNr */ ++ ++ /* tag component originalCalledNr (0xa2,len) */ + 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, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0), buffer, i); +- ASN1_PUSH(compstk, compsp, comp); +- 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)); +- if (j < 0) ++ ++ size = rose_presented_number_unscreened_encode(pri, &buffer[i], call->redirectingpres, typeofnumber_from_q931(pri, (call->redirectingplan & 0x70) >> 4), call->redirectingnum); ++ if (size < 0) ++ return -1; ++ i += size; ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++#endif ++ ++ /* redirectingName */ ++ if (call->redirectingname[0]) { ++ /* tag component redirectingName (0xa3,len) */ ++ ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3), buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* tag component namePresentationAllowedSimple (0x80,len) */ ++ ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* namePresentationAllowedSimple, implicid NameData */ ++ size = rose_namedata_encode(pri, &buffer[i], 1, call->redirectingname); ++ if (size < 0) ++ return -1; ++ i += size; ++ ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++ } ++ ++ /* originalCalledName */ ++ /* - not included - */ ++ ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++ ++ if (pri_call_apdu_queue(call, Q931_SETUP, buffer, i, NULL, NULL)) ++ return -1; ++ ++ return 0; ++} ++ ++static int rose_diverting_leg_information3_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len) ++{ ++ int i = 0; ++ struct nameelements_name redirectionname = { "", CHARACTER_SET_UNKNOWN, 0 }; ++ int presentation_allowed_indicator; ++ struct rose_component *comp = NULL; ++ unsigned char *vdata = sequence->data; ++ int size = 0; ++ ++ /* Data checks */ ++ if (sequence->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */ ++ pri_message(pri, "Invalid DivertingLegInformation3Type argument\n"); ++ return -1; ++ } ++ ++ if (sequence->len == ASN1_LEN_INDEF) { ++ len -= 4; /* For the 2 extra characters at the end ++ and two characters of header */ ++ } else ++ len -= 2; ++ ++ do { ++ /* presentationAllowedIndicator */ ++ GET_COMPONENT(comp, i, vdata, len); ++ CHECK_COMPONENT(comp, ASN1_BOOLEAN, "Don't know what to do if presentationAllowedIndicator is of type 0x%x\n"); ++ ASN1_GET_INTEGER(comp, presentation_allowed_indicator); ++ NEXT_COMPONENT(comp, i); ++ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " Received presentationAllowedIndicator: %d\n", presentation_allowed_indicator); ++ ++ /* Type SEQUENCE specifies an ordered list of component types. * ++ * We decode all components but for simplicity we don't check the order. */ ++ while (i < len) { ++ GET_COMPONENT(comp, i, vdata, len); ++ ++ switch(comp->type) { ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): ++ /* redirectionName */ ++ size = rose_name_decode(pri, comp->data, comp->len, &redirectionname); ++ if (size < 0) + return -1; +- +- i += j; +- ASN1_FIXUP(compstk, compsp, buffer, i); +- ASN1_FIXUP(compstk, compsp, buffer, i); ++ i += (size + 2); ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " Received RedirectionName '%s', namepres %s(%d), characterset %s(%d)\n", ++ redirectionname.name, namepres_to_str(redirectionname.namepres), redirectionname.namepres, ++ characterset_to_str(redirectionname.characterset), redirectionname.characterset); + break; ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1): /* [1] IMPLICIT Extension */ ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_2): /* [2] IMPLICIT SEQUENCE OF Extension */ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "!! Ignoring DivertingLegInformation3 component 0x%X\n", comp->type); ++ NEXT_COMPONENT(comp, i); ++ break; ++ default: ++ pri_message(pri, "!! Invalid DivertingLegInformation3 component received 0x%X\n", comp->type); ++ return -1; + } +- /* fall through */ +- case PRES_PROHIB_USER_NUMBER_PASSED_SCREEN: +- case PRES_PROHIB_USER_NUMBER_NOT_SCREENED: +- 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, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), buffer, i); +- break; +- default: +- pri_message(pri, "!! Undefined presentation value for redirecting number: %d\n", call->redirectingpres); +- case PRES_NUMBER_NOT_AVAILABLE: +- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i); +- break; ++ } ++ ++ call->divleginfo3activeflag = 1; ++ if ((redirectionname.namepres != 0) && (presentation_allowed_indicator != 0)) { ++ libpri_copy_string(call->divertedtoname, redirectionname.name, sizeof(call->divertedtoname)); ++ } else { ++ call->divertedtoname[0] = '\0'; ++ } ++ ++ return 0; + } +- ASN1_FIXUP(compstk, compsp, buffer, i); +- +- /* Fix length of stacked components */ +- while(compsp > 0) { ++ while (0); ++ ++ return -1; ++} ++ ++int rose_diverting_leg_information3_encode(struct pri *pri, q931_call *call, int messagetype) ++{ ++ int i = 0, compsp = 0; ++ struct rose_component *comp, *compstk[10]; ++ unsigned char buffer[256]; ++ int size; ++ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " Encode divertingLegInformation3\n"); ++ ++ /* Protocol Profile = 0x1f (Networking Extensions) (0x9f) */ ++ buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS); ++ ++ /* Network Facility Extension */ ++ if (pri->switchtype == PRI_SWITCH_QSIG) { ++ /* tag component NetworkFacilityExtension (0xaa, len ) */ ++ ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* sourceEntity (0x80,0x01,0x00) */ ++ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0); /* endPINX(0) */ ++ ++ /* destinationEntity (0x82,0x01,0x00) */ ++ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0); /* endPINX(0) */ + ASN1_FIXUP(compstk, compsp, buffer, i); + } +- +- if (pri_call_apdu_queue(call, Q931_SETUP, buffer, i, NULL, NULL)) ++ ++ /* Network Protocol Profile */ ++ /* - not included - */ ++ ++ /* Interpretation APDU (0x8b,0x01,0x00) */ ++ ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0); /* discardAnyUnrecognisedInvokePdu(0) */ ++ ++ /* Service APDU(s): */ ++ ++ /* ROSE InvokePDU (0xa1,len) */ ++ ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* ROSE InvokeID (0x02,0x01,invokeid) */ ++ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri)); ++ ++ /* ROSE operationId (0x02,0x01,0x16)*/ ++ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, ROSE_DIVERTING_LEG_INFORMATION3); ++ ++ /* constructor component (0x30,len) */ ++ ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* 'connectedpres' also indicates if name presentation is allowed */ ++ if (((call->divertedtopres & 0x60) >> 5) == 0) { ++ /* presentation allowed */ ++ ++ /* presentationAllowedIndicator (0x01,0x01,0xff) */ ++ ASN1_ADD_BYTECOMP(comp, ASN1_BOOLEAN, buffer, i, 0xff); /* true(255) */ ++ ++ /* redirectionName */ ++ ++ /* tag component redirectionName (0xa0,len) */ ++ ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0), buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ if (call->divertedtoname[0]) { ++ /* tag component namePresentationAllowedSimple (0x80,len) */ ++ ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* namePresentationAllowedSimple, implicid NameData */ ++ size = rose_namedata_encode(pri, &buffer[i], 1, call->divertedtoname); ++ if (size < 0) ++ return -1; ++ i += size; ++ ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++ } ++ ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++ } else { ++ /* presentation restricted */ ++ ++ /* presentationAllowedIndicator (0x01,0x01,0x00) */ ++ ASN1_ADD_BYTECOMP(comp, ASN1_BOOLEAN, buffer, i, 0); /* false(0) */ ++ ++ /* - don't include redirectionName, component is optional - */ ++ } ++ ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++ ++ if (pri_call_apdu_queue(call, messagetype, buffer, i, NULL, NULL)) + return -1; +- ++ + return 0; + } + +@@ -1644,7 +2828,7 @@ + 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) ++ if(rose_presented_number_unscreened_decode(pri, comp1->data, comp1->len, &chargednr) != 0) + return -1; + pri_message(pri, "!! not handled: Received ChargedNr '%s' \n", chargednr.partyaddress); + pri_message(pri, " ton = %d, pres = %d, npi = %d\n", chargednr.ton, chargednr.pres, chargednr.npi); +@@ -1740,302 +2924,407 @@ + } + /* End AOC */ + +-static int rose_calling_name_decode(struct pri *pri, q931_call *call, struct rose_component *choice, int len) ++/* ===== Call Transfer Supplementary Service (ECMA-178) ===== */ ++ ++static int rose_call_transfer_complete_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len) + { + int i = 0; + struct rose_component *comp = NULL; +- unsigned char *vdata = choice->data; +- int characterSet = 1; +- switch (choice->type) { +- case ROSE_NAME_PRESENTATION_ALLOWED_SIMPLE: +- memcpy(call->callername, choice->data, choice->len); +- call->callername[choice->len] = 0; +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " Received simple calling name '%s'\n", call->callername); +- return 0; ++ unsigned char *vdata = sequence->data; ++ int size = 0; + +- case ROSE_NAME_PRESENTATION_ALLOWED_EXTENDED: +- do { +- GET_COMPONENT(comp, i, vdata, len); +- CHECK_COMPONENT(comp, ASN1_OCTETSTRING, "Don't know what to do if nameData is of type 0x%x\n"); +- memcpy(call->callername, comp->data, comp->len); +- call->callername[comp->len] = 0; +- NEXT_COMPONENT(comp, i); ++ struct addressingdataelements_presentednumberscreened redirection_number; ++ struct nameelements_name redirectionname = { "", CHARACTER_SET_UNKNOWN, 0 }; ++ char basiccallinfoelements[257] = ""; ++ int call_status = 0; /* answered(0) */ ++ int end_designation; + +- GET_COMPONENT(comp, i, vdata, len); +- CHECK_COMPONENT(comp, ASN1_INTEGER, "Don't know what to do if CharacterSet is of type 0x%x\n"); +- ASN1_GET_INTEGER(comp, characterSet); +- } +- while (0); +- +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " Received extended calling name '%s', characterset %d\n", call->callername, characterSet); +- return 0; +- case ROSE_NAME_PRESENTATION_RESTRICTED_SIMPLE: +- case ROSE_NAME_PRESENTATION_RESTRICTED_EXTENDED: +- case ROSE_NAME_PRESENTATION_RESTRICTED_NULL: +- case ROSE_NAME_NOT_AVAIL: +- default: +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, "Do not handle argument of type 0x%X\n", choice->type); +- return -1; ++ /* Data checks */ ++ if (sequence->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */ ++ pri_message(pri, "Invalid callTransferComplete argument. (Not a sequence)\n"); ++ return -1; + } +-} +-/* ===== Call Transfer Supplementary Service (ECMA-178) ===== */ + +-static int rose_party_number_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value) +-{ +- int i = 0; +- int size = 0; +- struct rose_component *comp = NULL; +- unsigned char *vdata = data; ++ if (sequence->len == ASN1_LEN_INDEF) { ++ len -= 4; /* For the 2 extra characters at the end ++ and two characters of header */ ++ } else ++ len -= 2; + ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " CT-Complete: len=%d\n", len); + ++ /* CTCompleteArg SEQUENCE */ + do { ++ /* endDesignation EndDesignation */ + GET_COMPONENT(comp, i, vdata, len); ++ CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Invalid endDesignation type 0x%X of ROSE callTransferComplete component received\n"); ++ ASN1_GET_INTEGER(comp, end_designation); ++ NEXT_COMPONENT(comp, i); ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " CT-Complete: Received endDesignation=%s(%d)\n", enddesignation_to_str(end_designation), end_designation); + +- switch(comp->type) { +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* [0] IMPLICIT NumberDigits -- default: unknownPartyNumber */ +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " PartyNumber: UnknownPartyNumber len=%d\n", len); +- size = rose_number_digits_decode(pri, call, comp->data, comp->len, value); +- if (size < 0) +- return -1; +- value->npi = PRI_NPI_UNKNOWN; +- value->ton = PRI_TON_UNKNOWN; +- break; ++ /* redirectionNumber PresentedNumberScreened */ ++ GET_COMPONENT(comp, i, vdata, len); ++ size = rose_presented_number_screened_decode(pri, (u_int8_t *)comp, comp->len + 2, &redirection_number); ++ if (size < 0) ++ return -1; ++ comp->len = size; ++ NEXT_COMPONENT(comp, i); ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " CT-Complete: Received redirectionNumber=%s\n", redirection_number.partyaddress); + +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1): /* [1] IMPLICIT PublicPartyNumber */ +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " PartyNumber: PublicPartyNumber len=%d\n", len); +- size = rose_public_party_number_decode(pri, call, comp->data, comp->len, value); +- if (size < 0) +- return -1; +- value->npi = PRI_NPI_E163_E164; +- break; ++ /* Type SEQUENCE specifies an ordered list of component types. * ++ * We decode all components but for simplicity we don't check the order. */ ++ while (i < len) { ++ GET_COMPONENT(comp, i, vdata, len); + +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] IMPLICIT NumberDigits -- not used: dataPartyNumber */ +- pri_message(pri, "!! PartyNumber: dataPartyNumber is reserved!\n"); +- size = rose_number_digits_decode(pri, call, comp->data, comp->len, value); ++ switch(comp->type) { ++ case (ASN1_APPLICATION): ++ /* basicCallInfoElements PSS1InformationElement OPTIONAL */ ++ size = asn1_name_decode((u_int8_t *)comp, comp->len + 2, basiccallinfoelements, sizeof(basiccallinfoelements)); + if (size < 0) + return -1; +- value->npi = PRI_NPI_X121 /* ??? */; +- value->ton = PRI_TON_UNKNOWN /* ??? */; ++ i += size; ++ if (pri->debug & PRI_DEBUG_APDU) { ++ int j; ++ pri_message(pri, " CT-Complete: Received basicCallInfoElements\n"); ++ pri_message(pri, " "); ++ for (j = 0; basiccallinfoelements[j] != '\0'; j++) ++ pri_message(pri, "%02x ", (u_int8_t)basiccallinfoelements[j]); ++ pri_message(pri, "\n"); ++ } + break; +- +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_4): /* [4] IMPLICIT NumberDigits -- not used: telexPartyNumber */ +- pri_message(pri, "!! PartyNumber: telexPartyNumber is reserved!\n"); +- size = rose_number_digits_decode(pri, call, comp->data, comp->len, value); ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0): /* [0] namePresentationAllowedSimple */ ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1): /* [1] namePresentationAllowedExtended */ ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2): /* [2] namePresentationRestrictedSimple */ ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] namePresentationRestrictedExtended */ ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_4): /* [4] nameNotAvailable */ ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_7): /* [7] namePresentationRestrictedNull */ ++ /* redirectionName Name OPTIONAL */ ++ size = rose_name_decode(pri, (u_int8_t *)comp, comp->len + 2, &redirectionname); + if (size < 0) + return -1; +- value->npi = PRI_NPI_F69 /* ??? */; +- value->ton = PRI_TON_UNKNOWN /* ??? */; ++ i += size; ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " CT-Complete: Received RedirectionName '%s', namepres %s(%d), characterset %s(%d)\n", ++ redirectionname.name, namepres_to_str(redirectionname.namepres), redirectionname.namepres, ++ characterset_to_str(redirectionname.characterset), redirectionname.characterset); + break; +- +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_5): /* [5] IMPLICIT PrivatePartyNumber */ ++ case (ASN1_ENUMERATED): ++ /* callStatus CallStatus DEFAULT answered */ ++ ASN1_GET_INTEGER(comp, call_status); ++ NEXT_COMPONENT(comp,i); + if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " PartyNumber: PrivatePartyNumber len=%d\n", len); +- size = rose_private_party_number_decode(pri, call, comp->data, comp->len, value); +- if (size < 0) +- return -1; +- value->npi = PRI_NPI_PRIVATE; ++ pri_message(pri, " CT-Complete: Received callStatus=%s(%d)\n", callstatus_to_str(call_status), call_status); + break; +- +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_8): /* [8] IMPLICIT NumberDigits -- not used: nationalStandatdPartyNumber */ +- pri_message(pri, "!! PartyNumber: nationalStandardPartyNumber is reserved!\n"); +- size = rose_number_digits_decode(pri, call, comp->data, comp->len, value); +- if (size < 0) +- return -1; +- value->npi = PRI_NPI_NATIONAL; +- value->ton = PRI_TON_NATIONAL; ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_9): /* [9] IMPLICIT Extension */ ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_10): /* [10] IMPLICIT SEQUENCE OF Extension */ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "!! CT-Complete: Ignoring CallTransferComplete component 0x%X\n", comp->type); ++ NEXT_COMPONENT(comp, i); + break; +- + default: +- pri_message(pri, "Invalid PartyNumber component 0x%X\n", comp->type); ++ pri_message(pri, "!! CT-Complete: Invalid CallTransferComplete component received 0x%X\n", comp->type); + return -1; ++ } + } +- ASN1_FIXUP_LEN(comp, size); ++ + if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " PartyNumber: '%s' size=%d len=%d\n", value->partyaddress, size, len); +- return size; ++ pri_message(pri, " CT-Complete: callStatus=%s(%d)\n", callstatus_to_str(call_status), call_status); ++ ++ call->ctcompleteflag = 1; ++ if ((redirection_number.pres & PRES_RESTRICTION) == PRES_ALLOWED) { ++ libpri_copy_string(call->ctcompletenum, redirection_number.partyaddress, sizeof(call->ctcompletenum)); ++ } else { ++ call->ctcompletenum[0] = '\0'; ++ } ++ call->ctcompletepres = redirection_number.pres; ++ call->ctcompleteplan = ((redirection_number.ton & 0x07) << 4) | (redirection_number.npi & 0x0f); ++ call->ctcompletecallstatus = call_status; ++ ++ if (redirectionname.namepres != 0) { ++ libpri_copy_string(call->ctcompletename, redirectionname.name, sizeof(call->ctcompletename)); ++ } else { ++ call->ctcompletename[0] = '\0'; ++ } ++ ++ return 0; + } + while (0); + + return -1; + } + +- +-static int rose_number_screened_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberscreened *value) ++static int rose_call_transfer_complete_encode(struct pri *pri, q931_call *call, int call_status) + { +- int i = 0; +- int size = 0; +- struct rose_component *comp = NULL; +- unsigned char *vdata = data; ++ int i = 0, compsp = 0; ++ struct rose_component *comp, *compstk[10]; ++ unsigned char buffer[256]; ++ int size; + +- int scrind = -1; ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " Encode CallTransferComplete\n"); + +- do { +- /* Party Number */ +- GET_COMPONENT(comp, i, vdata, len); +- size = rose_party_number_decode(pri, call, (u_int8_t *)comp, comp->len + 2, (struct addressingdataelements_presentednumberunscreened*) value); ++ /* Protocol Profile = 0x1f (Networking Extensions) (0x9f) */ ++ buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS); ++ ++ /* Network Facility Extension */ ++ if (pri->switchtype == PRI_SWITCH_QSIG) { ++ /* tag component NetworkFacilityExtension (0xaa, len ) */ ++ ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* sourceEntity (0x80,0x01,0x00) */ ++ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0); /* endPINX(0) */ ++ ++ /* destinationEntity (0x82,0x01,0x00) */ ++ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0); /* endPINX(0) */ ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++ } ++ ++ /* Network Protocol Profile */ ++ /* - not included - */ ++ ++ /* Interpretation APDU (0x8b,0x01,0x00) */ ++ ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0); /* discardAnyUnrecognisedInvokePdu(0) */ ++ ++ /* Service APDU(s): */ ++ ++ /* ROSE InvokePDU (0xa1,len) */ ++ ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* ROSE InvokeID (0x02,0x01,invokeid) */ ++ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri)); ++ ++ /* ROSE operationId (0x02,0x01,0x0c)*/ ++ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, ROSE_CALL_TRANSFER_COMPLETE); ++ ++ ++ /* CTCompleteArg */ ++ ++ /* constructor component (0x30,len) */ ++ ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ ++ /* endDesignation (0x0a,0x01,0x00) */ ++ ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 0); /* primaryEnd(0) */ ++ ++ ++ /* redirectionNumber PresentedNumberScreened */ ++ ++ /* tag component presentationAllowedAddress (0xa0,len) */ ++ ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0), buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* presentationAllowedAddress, implicit NumberScreened */ ++ size = rose_number_screened_encode(pri, &buffer[i], 1, typeofnumber_from_q931(pri, (call->connectedplan & 0x70) >> 4), call->connectedpres & 0x03, call->connectednum); ++ if (size < 0) ++ return -1; ++ i += size; ++ ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++ ++ /* basicCallInfoElements */ ++ /* - not included - */ ++ ++#if 0 ++ /* basicCallInfoElements (0x40,0x00) */ ++ ASN1_ADD_SIMPLE(comp, (ASN1_APPLICATION| ASN1_TAG_0), buffer, i); ++#endif ++ ++ /* redirectionName */ ++ if (call->connectedname[0]) { ++ /* tag component namePresentationAllowedSimple (0x80,len) */ ++ ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* namePresentationAllowedSimple, implicid NameData */ ++ size = rose_namedata_encode(pri, &buffer[i], 1, call->connectedname); + if (size < 0) + return -1; +- comp->len = size; +- NEXT_COMPONENT(comp, i); ++ i += size; + +- /* Screening Indicator */ +- GET_COMPONENT(comp, i, vdata, len); +- CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Don't know what to do with NumberScreened ROSE component type 0x%x\n"); +- ASN1_GET_INTEGER(comp, scrind); +- // Todo: scrind = screeningindicator_for_q931(pri, scrind); +- NEXT_COMPONENT(comp, i); ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++ } + +- value->scrind = scrind; ++ if (call_status) { ++ /* callStatus (0x0a,0x01,0x01) */ ++ ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 1); /* alerting(1) */ ++ } else { ++ /* callStatus */ ++ /* - not included, default: answered(0) - */ ++#if 0 ++ /* callStatus (0x0a,0x01,0x00) */ ++ ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 0); /* answered(0) */ ++#endif ++ } + +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " NumberScreened: '%s' ScreeningIndicator=%d i=%d len=%d\n", value->partyaddress, scrind, i, len); ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++ ASN1_FIXUP(compstk, compsp, buffer, i); + +- return i-2; // We do not have a sequence header here. +- } +- while (0); ++ if (pri_call_apdu_queue(call, Q931_FACILITY, buffer, i, NULL, NULL)) ++ return -1; + +- return -1; ++ return 0; + } + +- +-static int rose_presented_number_screened_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberscreened *value) ++static int rose_call_transfer_active_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len) + { + int i = 0; ++ struct rose_component *comp = NULL; ++ unsigned char *vdata = sequence->data; + int size = 0; +- struct rose_component *comp = NULL; +- unsigned char *vdata = data; + +- /* Fill in default values */ +- value->ton = PRI_TON_UNKNOWN; +- value->npi = PRI_NPI_UNKNOWN; +- value->pres = -1; /* Data is not available */ ++ struct addressingdataelements_presentedaddressscreened connectedaddress; ++ struct nameelements_name connectedname = { "", CHARACTER_SET_UNKNOWN, 0 }; ++ char basiccallinfoelements[257] = ""; + ++ /* Data checks */ ++ if (sequence->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */ ++ pri_message(pri, "Invalid callTransferActive argument. (Not a sequence)\n"); ++ return -1; ++ } ++ ++ if (sequence->len == ASN1_LEN_INDEF) { ++ len -= 4; /* For the 2 extra characters at the end ++ and two characters of header */ ++ } else ++ len -= 2; ++ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " CT-Active: len=%d\n", len); ++ ++ /* CTActiveArg SEQUENCE */ + do { ++ /* connectedAddress PresentedAddressScreened */ + GET_COMPONENT(comp, i, vdata, len); ++ size = rose_presented_address_screened_decode(pri, (u_int8_t *)comp, comp->len + 2, &connectedaddress); ++ if (size < 0) ++ return -1; ++ comp->len = size; ++ NEXT_COMPONENT(comp, i); ++ if (pri->debug & PRI_DEBUG_APDU) { ++ pri_message(pri, " CT-Active: Received connectedAddress=%s\n", connectedaddress.partyaddress); ++ } + +- switch(comp->type) { +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* [0] IMPLICIT presentationAllowedNumber */ +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " PresentedNumberScreened: presentationAllowedNumber comp->len=%d\n", comp->len); +- value->pres = PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN; +- size = rose_number_screened_decode(pri, call, comp->data, comp->len, value); ++ /* Type SEQUENCE specifies an ordered list of component types. * ++ * We decode all components but for simplicity we don't check the order. */ ++ while (i < len) { ++ GET_COMPONENT(comp, i, vdata, len); ++ ++ switch(comp->type) { ++ case (ASN1_APPLICATION): ++ /* basiccallinfoelements PSS1InformationElement OPTIONAL */ ++ size = asn1_name_decode((u_int8_t *)comp, comp->len + 2, basiccallinfoelements, sizeof(basiccallinfoelements)); + if (size < 0) + return -1; +- ASN1_FIXUP_LEN(comp, size); +- return size + 2; +- +- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1): /* [1] IMPLICIT presentationRestricted */ +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " PresentedNumberScreened: presentationRestricted comp->len=%d\n", comp->len); +- if (comp->len != 0) { /* must be NULL */ +- pri_error(pri, "!! Invalid PresentationRestricted component received (len != 0)\n"); +- return -1; ++ i += size; ++ if (pri->debug & PRI_DEBUG_APDU) { ++ int j; ++ pri_message(pri, " CT-Active: Received basicCallInfoElements\n"); ++ pri_message(pri, " "); ++ for (j = 0; basiccallinfoelements[j] != '\0'; j++) ++ pri_message(pri, "%02x ", (u_int8_t)basiccallinfoelements[j]); ++ pri_message(pri, "\n"); + } +- value->pres = PRES_PROHIB_USER_NUMBER_PASSED_SCREEN; +- return 2; +- +- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2): /* [2] IMPLICIT numberNotAvailableDueToInterworking */ +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " PresentedNumberScreened: NumberNotAvailableDueToInterworking comp->len=%d\n", comp->len); +- if (comp->len != 0) { /* must be NULL */ +- pri_error(pri, "!! Invalid NumberNotAvailableDueToInterworking component received (len != 0)\n"); ++ break; ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0): /* [0] namePresentationAllowedSimple */ ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1): /* [1] namePresentationAllowedExtended */ ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2): /* [2] namePresentationRestrictedSimple */ ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] namePresentationRestrictedExtended */ ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_4): /* [4] nameNotAvailable */ ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_7): /* [7] namePresentationRestrictedNull */ ++ /* connectedName Name OPTIONAL */ ++ size = rose_name_decode(pri, (u_int8_t *)comp, comp->len + 2, &connectedname); ++ if (size < 0) + return -1; +- } +- value->pres = PRES_NUMBER_NOT_AVAILABLE; ++ i += size; + if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " PresentedNumberScreened: numberNotAvailableDueToInterworking Type=0x%X i=%d len=%d size=%d\n", comp->type, i, len); +- return 2; +- +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] IMPLICIT presentationRestrictedNumber */ ++ pri_message(pri, " CT-Active: Received ConnectedName '%s', namepres %s(%d), characterset %s(%d)\n", ++ connectedname.name, namepres_to_str(connectedname.namepres), connectedname.namepres, ++ characterset_to_str(connectedname.characterset), connectedname.characterset); ++ break; ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_9): /* [9] IMPLICIT Extension */ ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_10): /* [10] IMPLICIT SEQUENCE OF Extension */ + if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " PresentedNumberScreened: presentationRestrictedNumber comp->len=%d\n", comp->len); +- value->pres = PRES_PROHIB_USER_NUMBER_PASSED_SCREEN; +- size = rose_number_screened_decode(pri, call, comp->data, comp->len, value); +- if (size < 0) +- return -1; +- ASN1_FIXUP_LEN(comp, size); +- return size + 2; ++ pri_message(pri, "!! CT-Active: Ignoring CallTransferActive component 0x%X\n", comp->type); ++ NEXT_COMPONENT(comp, i); ++ break; ++ default: ++ pri_message(pri, "!! CT-Active: Invalid CallTransferActive component received 0x%X\n", comp->type); ++ return -1; ++ } ++ } + +- default: +- pri_message(pri, "Invalid PresentedNumberScreened component 0x%X\n", comp->type); ++ call->ctactiveflag = 1; ++ if ((connectedaddress.pres & PRES_RESTRICTION) == PRES_ALLOWED) { ++ libpri_copy_string(call->ctactivenum, connectedaddress.partyaddress, sizeof(call->ctactivenum)); ++ } else { ++ call->ctactivenum[0] = '\0'; + } +- return -1; ++ call->ctactivepres = connectedaddress.pres; ++ call->ctactiveplan = ((connectedaddress.ton & 0x07) << 4) | (connectedaddress.npi & 0x0f); ++ ++ if (connectedname.namepres != 0) { ++ libpri_copy_string(call->ctactivename, connectedname.name, sizeof(call->ctactivename)); ++ } else { ++ call->ctactivename[0] = '\0'; ++ } ++ ++ return 0; + } + while (0); + + return -1; + } + +- +-static int rose_call_transfer_complete_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len) ++#if 0 ++static int rose_call_transfer_update_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len) + { + int i = 0; + struct rose_component *comp = NULL; + unsigned char *vdata = sequence->data; + int res = 0; + +- int end_designation = 0; + struct addressingdataelements_presentednumberscreened redirection_number; +- char redirection_name[50] = ""; +- int call_status = 0; + redirection_number.partyaddress[0] = 0; +- redirection_number.partysubaddress[0] = 0; ++ char redirection_name[51] = ""; + call->callername[0] = 0; + call->callernum[0] = 0; + +- + /* Data checks */ + if (sequence->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */ +- pri_message(pri, "Invalid callTransferComplete argument. (Not a sequence)\n"); ++ pri_message(pri, "Invalid callTransferUpdate argument. (Not a sequence)\n"); + return -1; + } + + if (sequence->len == ASN1_LEN_INDEF) { +- len -= 4; /* For the 2 extra characters at the end +- * and two characters of header */ ++ len -= 4; /* For the 2 extra characters at the end ++ and two characters of header */ + } else + len -= 2; + + if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " CT-Complete: len=%d\n", len); ++ pri_message(pri, " CT-Update: len=%d\n", len); + + do { +- /* End Designation */ +- GET_COMPONENT(comp, i, vdata, len); +- CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Invalid endDesignation type 0x%X of ROSE callTransferComplete component received\n"); +- ASN1_GET_INTEGER(comp, end_designation); +- NEXT_COMPONENT(comp, i); +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " CT-Complete: Received endDesignation=%d\n", end_designation); +- +- + /* Redirection Number */ + GET_COMPONENT(comp, i, vdata, len); +- res = rose_presented_number_screened_decode(pri, call, (u_int8_t *)comp, comp->len + 2, &redirection_number); ++ res = rose_presented_number_screened_decode(pri, (u_int8_t *)comp, comp->len + 2, &redirection_number); + if (res < 0) + return -1; + comp->len = res; + if (res > 2) { + if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " CT-Complete: Received redirectionNumber=%s\n", redirection_number.partyaddress); ++ pri_message(pri, " CT-Update: Received redirectionNumber=%s\n", redirection_number.partyaddress); + strncpy(call->callernum, redirection_number.partyaddress, 20); + call->callernum[20] = 0; + } + NEXT_COMPONENT(comp, i); + +- +-#if 0 /* This one is optional. How do we check if it is there? */ +- /* Basic Call Info Elements */ +- GET_COMPONENT(comp, i, vdata, len); +- NEXT_COMPONENT(comp, i); +-#endif +- +- + /* Redirection Name */ + GET_COMPONENT(comp, i, vdata, len); + res = asn1_name_decode((u_int8_t *)comp, comp->len + 2, redirection_name, sizeof(redirection_name)); +@@ -2047,16 +3336,14 @@ + comp->len = res; + NEXT_COMPONENT(comp, i); + if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " CT-Complete: Received redirectionName '%s'\n", redirection_name); ++ pri_message(pri, " CT-Update: Received redirectionName '%s'\n", redirection_name); + + +- /* Call Status */ ++#if 0 /* This one is optional. How do we check if it is there? */ ++ /* Basic Call Info Elements */ + GET_COMPONENT(comp, i, vdata, len); +- CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Invalid callStatus type 0x%X of ROSE callTransferComplete component received\n"); +- ASN1_GET_INTEGER(comp, call_status); + NEXT_COMPONENT(comp, i); +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " CT-Complete: Received callStatus=%d\n", call_status); ++#endif + + + /* Argument Extension */ +@@ -2078,8 +3365,8 @@ + comp->len = res; + + default: +- pri_message(pri, " CT-Complete: !! Unknown argumentExtension received 0x%X\n", comp->type); +- return -1; ++ pri_message(pri, " CT-Update: !! Unknown argumentExtension received 0x%X\n", comp->type); ++ return -1; + } + #else + GET_COMPONENT(comp, i, vdata, len); +@@ -2088,7 +3375,7 @@ + #endif + + if(i < len) +- pri_message(pri, " CT-Complete: !! not all information is handled !! i=%d / len=%d\n", i, len); ++ pri_message(pri, " CT-Update: !! not all information is handled !! i=%d / len=%d\n", i, len); + + return 0; + } +@@ -2096,26 +3383,422 @@ + + return -1; + } ++#endif + ++/* ===== End Call Transfer Supplementary Service (ECMA-178) ===== */ + +-static int rose_call_transfer_update_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len) ++ ++ ++static int rose_calling_name_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len) + { ++ struct nameelements_name callingname; ++ int res; ++ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " Handle callingName\n"); ++ ++ res = rose_name_decode(pri, (u_int8_t *)sequence, sequence->len + 2, &callingname); ++ if (res < 0) ++ return -1; ++ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " Received CallingName '%s', namepres: %s(%d), characterset %s(%d)\n", ++ callingname.name, namepres_to_str(callingname.namepres), callingname.namepres, ++ characterset_to_str(callingname.characterset), callingname.characterset); ++ ++ if (callingname.namepres >= 0) { ++ libpri_copy_string(call->callername, callingname.name, sizeof(call->callername)); ++ } ++ ++ return 0; ++} ++ ++static int rose_called_name_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len) ++{ ++ struct nameelements_name calledname; ++ int res; ++ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " Handle calledName\n"); ++ ++ res = rose_name_decode(pri, (u_int8_t *)sequence, sequence->len + 2, &calledname); ++ if (res < 0) ++ return -1; ++ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " Received CalledName '%s', namepres %s(%d), characterset %s(%d)\n", ++ calledname.name, namepres_to_str(calledname.namepres), calledname.namepres, ++ characterset_to_str(calledname.characterset), calledname.characterset); ++ ++ if (calledname.namepres != 0) { ++ libpri_copy_string(call->calledname, calledname.name, sizeof(call->calledname)); ++ } else { ++ call->calledname[0] = '\0'; ++ } ++ ++ return 0; ++} ++ ++int rose_called_name_encode(struct pri *pri, q931_call *call, int messagetype) ++{ ++ int i = 0, compsp = 0; ++ struct rose_component *comp, *compstk[10]; ++ unsigned char buffer[256]; ++ int size; ++ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " Encode calledName\n"); ++ ++ /* Protocol Profile = 0x1f (Networking Extensions) (0x9f) */ ++ buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS); ++ ++ /* Network Facility Extension */ ++ if (pri->switchtype == PRI_SWITCH_QSIG) { ++ /* tag component NetworkFacilityExtension (0xaa, len ) */ ++ ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* sourceEntity (0x80,0x01,0x00) */ ++ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0); /* endPINX(0) */ ++ ++ /* destinationEntity (0x82,0x01,0x00) */ ++ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0); /* endPINX(0) */ ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++ } ++ ++ /* Network Protocol Profile */ ++ /* - not included - */ ++ ++ /* Interpretation APDU (0x8b,0x01,0x00) */ ++ ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0); /* discardAnyUnrecognisedInvokePdu(0) */ ++ ++ /* Service APDU(s): */ ++ ++ /* ROSE InvokePDU (0xa1,len) */ ++ ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* ROSE InvokeID (0x02,0x01,invokeid) */ ++ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri)); ++ ++ /* ROSE operationId (0x02,0x01,0x02)*/ ++ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, SS_CNOP_CALLEDNAME); ++ ++ /* tag component namePresentationAllowedSimple (0x80,len) */ ++ ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* namePresentationAllowedSimple, implicid NameData */ ++ size = rose_namedata_encode(pri, &buffer[i], 1, call->connectedname); ++ if (size < 0) ++ return -1; ++ i += size; ++ ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++ ++ if (pri_call_apdu_queue(call, messagetype, buffer, i, NULL, NULL)) ++ return -1; ++ ++ return 0; ++} ++ ++static int rose_connected_name_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len) ++{ ++ struct nameelements_name connectedname; ++ int res; ++ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " Handle connectedName\n"); ++ ++ res = rose_name_decode(pri, (u_int8_t *)sequence, sequence->len + 2, &connectedname); ++ if (res < 0) ++ return -1; ++ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " Received ConnectedName '%s', namepres %s(%d), characterset %s(%d)\n", ++ connectedname.name, namepres_to_str(connectedname.namepres), connectedname.namepres, ++ characterset_to_str(connectedname.characterset), connectedname.characterset); ++ ++ if (connectedname.namepres != 0) { ++ libpri_copy_string(call->connectedname, connectedname.name, sizeof(call->connectedname)); ++ } else { ++ call->connectedname[0] = '\0'; ++ } ++ ++ return 0; ++} ++ ++int rose_connected_name_encode(struct pri *pri, q931_call *call, int messagetype) ++{ ++ int i = 0, compsp = 0; ++ struct rose_component *comp, *compstk[10]; ++ unsigned char buffer[256]; ++ int size; ++ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " Encode connectedName\n"); ++ ++ /* Protocol Profile = 0x1f (Networking Extensions) (0x9f) */ ++ buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS); ++ ++ /* Network Facility Extension */ ++ if (pri->switchtype == PRI_SWITCH_QSIG) { ++ /* tag component NetworkFacilityExtension (0xaa, len ) */ ++ ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* sourceEntity (0x80,0x01,0x00) */ ++ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0); /* endPINX(0) */ ++ ++ /* destinationEntity (0x82,0x01,0x00) */ ++ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0); /* endPINX(0) */ ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++ } ++ ++ /* Network Protocol Profile */ ++ /* - not included - */ ++ ++ /* Interpretation APDU (0x8b,0x01,0x00) */ ++ ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0); /* discardAnyUnrecognisedInvokePdu(0) */ ++ ++ /* Service APDU(s): */ ++ ++ /* ROSE InvokePDU (0xa1,len) */ ++ ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* ROSE InvokeID (0x02,0x01,invokeid) */ ++ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri)); ++ ++ /* ROSE operationId (0x02,0x01,0x02)*/ ++ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, SS_CNOP_CONNECTEDNAME); ++ ++ /* tag component namePresentationAllowedSimple (0x80,len) */ ++ ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* namePresentationAllowedSimple, implicid NameData */ ++ size = rose_namedata_encode(pri, &buffer[i], 1, call->connectedname); ++ if (size < 0) ++ return -1; ++ i += size; ++ ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++ ++ if (pri_call_apdu_queue(call, messagetype, buffer, i, NULL, NULL)) ++ return -1; ++ ++ return 0; ++} ++ ++/* ===== Begin Call Completion Supplementary Service (ETS 300 366/ECMA 186) ===== */ ++/* operationId e.g. QSIG_CCBSRINGOUT, QSIG_CC_CANCEL */ ++int add_qsigCcInv_facility_ie (struct pri *pri, q931_call *c, int messagetype) ++{ + int i = 0; ++ unsigned char buffer[256]; ++ struct rose_component *comp = NULL, *compstk[10]; ++ int compsp = 0; ++ u_int8_t operationId = c->ccoperation; ++ ++ /* 1 Byte 0x80 | 0x1F = 9F Protocol Profile */ ++ buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS); ++ ++ /* Interpretation component */ ++ ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i); /* 2. Byte NEtwork Facility Extension 0xAA = ASN1_CONTEXT_SPECIFIC(0x80) | (ASN1_CONSTRUCTOR 0x20) 0x0A (Tag laut Standard) */ ++ ASN1_PUSH(compstk, compsp, comp); ++ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0); /* (0x80, 0x01(len), 0x00) endPTNX */ ++ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0); /* (0x82, 0x01(len), 0x00) endPTNX */ ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++ ++ ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0); /* 0x8B, 0x01(len), 0x00 discard */ ++ ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i); /* 0xA1, 0xXX (len of Invoke Sequenz) invoke APDU */ ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* Invoke ID */ ++ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri)); /* 0x02 0x01 0xXX */ ++ ++ /* Operation ID: QSIG_CCBSRINGOUT, QSIG_CC_CANCEL */ ++ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, operationId); /* 0x02 0x01 0x1f/0x1c */ ++ ++ /* CcExtension */ ++ ASN1_ADD_SIMPLE(comp, ASN1_NULL, buffer, i); /* 0x05 0x00 */ ++ ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++ ++ if (pri_call_apdu_queue(c, messagetype, buffer, i, NULL, NULL)) ++ return -1; ++ ++ return 0; ++} ++ ++static int rose_cc_ringout_inv_decode(struct pri *pri, struct qsig_cc_extension *cc_extension, struct rose_component *choice, int len) { ++ int i = 0; ++ cc_extension->cc_extension_tag = 0; ++ ++ do { ++ switch(choice->type) { ++ case (ASN1_NULL): /* none NULL */ ++ cc_extension->cc_extension_tag = ASN1_NULL; ++ return 0; ++ ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_14): /* single [14] IMPLICIT Extension */ ++ cc_extension->cc_extension_tag = ASN1_TAG_14; ++ return 0; ++ ++ ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_15): /* multiple [15] IMPLICIT SEQUENCE OF Extension */ ++ cc_extension->cc_extension_tag = ASN1_TAG_15; ++ return 0; ++ ++ default: ++ if (choice->type == 0 && choice->len == 0) { ++ return 0; ++ } ++ pri_message(pri, "!! Invalid ss-cc-optional-Arg component received 0x%X\n", choice->type); ++ return -1; ++ } ++ ++ if (i < len) ++ pri_message(pri, " ss-cc-extension: !! not all information is handled !! i=%d / len=%d\n", i, len); ++ ++ return 0; ++ } ++ while (0); ++ ++ return -1; ++} ++ ++static int rose_cc_optional_arg_decode(struct pri *pri, q931_call *call, struct qsig_cc_optional_arg *cc_optional_arg , struct rose_component *choice, int len) { ++ int i = 0; ++ int res = 0; + struct rose_component *comp = NULL; ++ unsigned char *vdata = choice->data; ++ struct addressingdataelements_presentednumberunscreened numberA; ++ struct addressingdataelements_presentednumberunscreened numberB; ++ ++ cc_optional_arg->cc_extension.cc_extension_tag = 0; ++ cc_optional_arg->number_A[0] = '\0'; ++ cc_optional_arg->number_B[0] = '\0'; ++ ++ do { ++ switch(choice->type) { ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* fullArg [0] IMPLICIT SEQUENCE */ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " ss-cc-optional-Arg: len=%d\n", len); ++ ++ numberA.partyaddress[0] = '\0'; ++ ++ /* numberA */ ++ GET_COMPONENT(comp, i, vdata, len); ++ res += rose_party_number_decode(pri, (u_int8_t *)comp, comp->len + 2, &numberA); ++ if (res < 0) ++ return -1; ++ comp->len = res; ++ if (res > 2) { ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " ss-cc-optional-Arg: Received numberA=%s\n", numberA.partyaddress); ++ strncpy(cc_optional_arg->number_A, numberA.partyaddress, 20); ++ cc_optional_arg->number_A[20] = '\0'; ++ } ++ NEXT_COMPONENT(comp, i); ++ ++ numberB.partyaddress[0] = '\0'; ++ ++ /* numberB */ ++ GET_COMPONENT(comp, i, vdata, len); ++ res = rose_party_number_decode(pri, (u_int8_t *)comp, comp->len + 2, &numberB); ++ if (res < 0) ++ return -1; ++ comp->len = res; ++ if (res > 2) { ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " ss-cc-optional-Arg: Received numberB=%s\n", numberB.partyaddress); ++ strncpy(cc_optional_arg->number_B, numberB.partyaddress, 20); ++ cc_optional_arg->number_B[20] = '\0'; ++ } ++ NEXT_COMPONENT(comp, i); ++ ++ /* service */ /* PSS1InformationElement */ ++ GET_COMPONENT(comp, i, vdata, len); ++ NEXT_COMPONENT(comp, i); ++ ++ /* optional */ ++ for (; i < len; NEXT_COMPONENT(comp, i)) { ++ GET_COMPONENT(comp, i, vdata, len); ++ switch(comp->type) { ++ case (ASN1_NULL): /* */ ++ cc_optional_arg->cc_extension.cc_extension_tag = ASN1_NULL; ++ NEXT_COMPONENT(comp, i); ++ break; ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_14): /* */ ++ NEXT_COMPONENT(comp, i); ++ break; ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_15): /* */ ++ NEXT_COMPONENT(comp, i); ++ break; ++ default: ++ if (comp->type == 0 && comp->len == 0) { ++ return 0; ++ break; /* Found termination characters */ ++ } ++ pri_message(pri, "!! Invalid ss-cc-optional-Arg component received 0x%X\n", comp->type); ++ return -1; ++ } ++ } ++ ++ if (i < len) ++ pri_message(pri, " ss-cc-optional-Arg: !! not all information is handled !! i=%d / len=%d\n", i, len); ++ ++ return 0; ++ ++ /* extArg CcExtension */ ++ case (ASN1_NULL): /* none NULL */ ++ cc_optional_arg->cc_extension.cc_extension_tag = ASN1_NULL; ++ return 0; ++ ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_14): /* single [14] IMPLICIT Extension */ ++ cc_optional_arg->cc_extension.cc_extension_tag = ASN1_TAG_14; ++ return 0; ++ ++ ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_15): /* multiple [15] IMPLICIT SEQUENCE OF Extension */ ++ cc_optional_arg->cc_extension.cc_extension_tag = ASN1_TAG_15; ++ return 0; ++ ++ default: ++ if (choice->type == 0 && choice->len == 0) { ++ return 0; ++ } ++ pri_message(pri, "!! Invalid ss-cc-optional-Arg component received 0x%X\n", choice->type); ++ return -1; ++ } ++ ++ if (i < len) ++ pri_message(pri, " ss-cc-optional-Arg: !! not all information is handled !! i=%d / len=%d\n", i, len); ++ ++ return 0; ++ } ++ while (0); ++ ++ return -1; ++} ++ ++static int rose_cc_request_result_decode(struct pri *pri, struct qsig_cc_request_res *cc_request_res , struct rose_component *sequence, int len) ++{ ++ int i = 0; ++ struct rose_component *comp = NULL; + unsigned char *vdata = sequence->data; +- int res = 0; + +- struct addressingdataelements_presentednumberscreened redirection_number; +- redirection_number.partyaddress[0] = 0; +- redirection_number.partysubaddress[0] = 0; +- char redirection_name[50] = ""; +- call->callername[0] = 0; +- call->callernum[0] = 0; ++ cc_request_res->no_path_reservation = 0; /* Default FALSE */ ++ cc_request_res->retain_service = 0; /* Default FALSE */ ++ cc_request_res->cc_extension.cc_extension_tag = 0; + +- + /* Data checks */ + if (sequence->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */ +- pri_message(pri, "Invalid callTransferComplete argument. (Not a sequence)\n"); ++ pri_message(pri, "Invalid cc request result argument. (Not a sequence)\n"); + return -1; + } + +@@ -2126,75 +3809,55 @@ + len -= 2; + + if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " CT-Complete: len=%d\n", len); ++ pri_message(pri, " CC-request-Return-Result: len=%d\n", len); + + do { +- /* Redirection Number */ +- GET_COMPONENT(comp, i, vdata, len); +- res = rose_presented_number_screened_decode(pri, call, (u_int8_t *)comp, comp->len + 2, &redirection_number); +- if (res < 0) +- return -1; +- comp->len = res; +- if (res > 2) { +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " CT-Complete: Received redirectionNumber=%s\n", redirection_number.partyaddress); +- strncpy(call->callernum, redirection_number.partyaddress, 20); +- call->callernum[20] = 0; +- } +- NEXT_COMPONENT(comp, i); ++ /* defaults and optional */ ++ for (; i < len; NEXT_COMPONENT(comp, i)) { ++ GET_COMPONENT(comp, i, vdata, len); ++ switch(comp->type) { ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0): ++ /* no-path-reservation */ ++ ASN1_GET_INTEGER(comp, cc_request_res->no_path_reservation); ++ NEXT_COMPONENT(comp, i); ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " cc request result: Received noPathReservation=%d\n", cc_request_res->no_path_reservation); ++ break; + +- /* Redirection Name */ +- GET_COMPONENT(comp, i, vdata, len); +- res = asn1_name_decode((u_int8_t *)comp, comp->len + 2, redirection_name, sizeof(redirection_name)); +- if (res < 0) +- return -1; +- memcpy(call->callername, comp->data, comp->len); +- call->callername[comp->len] = 0; +- ASN1_FIXUP_LEN(comp, res); +- comp->len = res; +- NEXT_COMPONENT(comp, i); +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " CT-Complete: Received redirectionName '%s'\n", redirection_name); ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1): ++ /* retain_service */ ++ ASN1_GET_INTEGER(comp, cc_request_res->retain_service); ++ NEXT_COMPONENT(comp, i); ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " cc request result: Received retainService=%d\n", cc_request_res->retain_service); ++ break; + ++ case (ASN1_NULL): /* */ ++ cc_request_res->cc_extension.cc_extension_tag = ASN1_NULL; ++ NEXT_COMPONENT(comp, i); ++ break; + +-#if 0 /* This one is optional. How do we check if it is there? */ +- /* Basic Call Info Elements */ +- GET_COMPONENT(comp, i, vdata, len); +- NEXT_COMPONENT(comp, i); +-#endif ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_14): ++ cc_request_res->cc_extension.cc_extension_tag = ASN1_TAG_14; ++ NEXT_COMPONENT(comp, i); ++ break; + ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_15): ++ cc_request_res->cc_extension.cc_extension_tag = ASN1_TAG_15; ++ NEXT_COMPONENT(comp, i); ++ break; + +- /* Argument Extension */ +-#if 0 /* Not supported */ +- GET_COMPONENT(comp, i, vdata, len); +- switch (comp->type) { +- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_9): /* [9] IMPLICIT Extension */ +- res = rose_extension_decode(pri, call, comp->data, comp->len, &redirection_number); +- if (res < 0) +- return -1; +- ASN1_FIXUP_LEN(comp, res); +- comp->len = res; +- +- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_10): /* [10] IMPLICIT SEQUENCE OF Extension */ +- res = rose_sequence_of_extension_decode(pri, call, comp->data, comp->len, &redirection_number); +- if (res < 0) +- return -1; +- ASN1_FIXUP_LEN(comp, res); +- comp->len = res; +- + default: +- pri_message(pri, " CT-Complete: !! Unknown argumentExtension received 0x%X\n", comp->type); ++ if (comp->type == 0 && comp->len == 0) { ++ break; /* Found termination characters */ ++ } ++ pri_message(pri, "!! Invalid ss-cc-optional-Arg component received 0x%X\n", comp->type); + return -1; ++ } + } +-#else +- GET_COMPONENT(comp, i, vdata, len); +- ASN1_FIXUP_LEN(comp, res); +- NEXT_COMPONENT(comp, i); +-#endif + +- if(i < len) +- pri_message(pri, " CT-Complete: !! not all information is handled !! i=%d / len=%d\n", i, len); +- ++ if (i < len) ++ pri_message(pri, " ss-cc-optional-Arg: !! not all information is handled !! i=%d / len=%d\n", i, len); + return 0; + } + while (0); +@@ -2202,11 +3865,18 @@ + return -1; + } + ++static int rose_ccbs_request_result_decode(struct pri *pri, struct qsig_cc_request_res *cc_request_res , struct rose_component *sequence, int len) ++{ ++ return rose_cc_request_result_decode(pri, cc_request_res , sequence, len); ++} + +-/* ===== End Call Transfer Supplementary Service (ECMA-178) ===== */ ++static int rose_ccnr_request_result_decode(struct pri *pri, struct qsig_cc_request_res *cc_request_res , struct rose_component *sequence, int len) ++{ ++ return rose_cc_request_result_decode(pri, cc_request_res , sequence, len); ++} ++/* ===== End Call Completion Supplementary Service (ETS 300 366/ECMA 186) ===== */ + + +- + int rose_reject_decode(struct pri *pri, q931_call *call, q931_ie *ie, unsigned char *data, int len) + { + int i = 0; +@@ -2267,7 +3937,7 @@ + + return 0; + } else { +- pri_message(pri, "Unable to handle return result on switchtype %d!\n", pri->switchtype); ++ pri_message(pri, "Unable to handle reject on switchtype %d!\n", pri->switchtype); + return -1; + } + +@@ -2275,6 +3945,20 @@ + + return -1; + } ++ ++ ++static struct subcommand *get_ptr_subcommand(struct subcommands *sub) ++{ ++ if (sub->counter_subcmd < MAX_SUBCOMMANDS) { ++ int count = sub->counter_subcmd; ++ sub->counter_subcmd++; ++ return &sub->subcmd[count]; ++ } ++ ++ return NULL; ++} ++ ++ + int rose_return_error_decode(struct pri *pri, q931_call *call, q931_ie *ie, unsigned char *data, int len) + { + int i = 0; +@@ -2283,6 +3967,7 @@ + unsigned char *vdata = data; + struct rose_component *comp = NULL; + char *invokeidstr, *errorstr; ++ struct subcommand *c_subcmd; + + do { + /* Invoke ID stuff */ +@@ -2329,9 +4014,39 @@ + pri_error(pri, "\tERROR: %s\n", errorstr); + + return 0; ++ } else if (pri->switchtype == PRI_SWITCH_QSIG) { ++ switch (errorvalue) { ++ case 1008: ++ errorstr = "Unspecified"; ++ break; ++ case 1012: ++ errorstr = "Remote user busy again"; ++ break; ++ case 1013: ++ errorstr = "Failure to match"; ++ break; ++ default: ++ errorstr = "Unknown"; ++ } ++ ++ c_subcmd = get_ptr_subcommand(&call->subcmds); ++ if (!c_subcmd) { ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "ROSE RETURN ERROR %i - more than %d facilities !\n", errorvalue, MAX_SUBCOMMANDS); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ return -1; ++ } ++ ++ if (pri->debug & PRI_DEBUG_APDU) ++ { ++ pri_message(pri, "ROSE RETURN RESULT %i: %s\n", errorvalue, errorstr); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ } ++ c_subcmd->cmd = CMD_CC_ERROR; ++ c_subcmd->cc_error.error_value = errorvalue; ++ return 0; + } else { +- pri_message(pri, "Unable to handle return result on switchtype %d!\n", pri->switchtype); +- return -1; ++ pri_message(pri, "Unable to handle return error on switchtype %d!\n", pri->switchtype); + } + + } while(0); +@@ -2346,6 +4061,8 @@ + int invokeidvalue = -1; + unsigned char *vdata = data; + struct rose_component *comp = NULL; ++ int res; ++ struct subcommand *c_subcmd; + + do { + /* Invoke ID stuff */ +@@ -2392,11 +4109,90 @@ + return -1; + } + } else if (pri->switchtype == PRI_SWITCH_QSIG) { +- switch (invokeidvalue) { +- case 0x13: +- if (pri->debug & PRI_DEBUG_APDU) pri_message(pri, "Successfully completed QSIG CF callRerouting!\n"); ++ int operation_tag; ++ ++ /* sequence is optional */ ++ if (i >= len) + return 0; ++ ++ /* Data checks, sequence is optional */ ++ GET_COMPONENT(comp, i, vdata, len); ++ if (comp->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */ ++ pri_message(pri, "No arguments on cc-return result\n"); ++ return 0; + } ++ ++ if (comp->len == ASN1_LEN_INDEF) { ++ len -= 2; /* For the 2 extra characters at the end*/ ++ } ++ ++ /* Traverse the contents of this sequence */ ++ SUB_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"); ++ 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; ++ ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " [ Handling operation %d ]\n", operation_tag); ++ switch (operation_tag) { ++ case QSIG_CF_CALLREROUTING: ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "Successfully completed QSIG CF callRerouting!\n"); ++ return 0; ++ ++ case QSIG_CC_CCBSREQUEST: ++ c_subcmd = get_ptr_subcommand(&call->subcmds); ++ if (!c_subcmd) { ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "ROSE %i: return_result CcCcbsRequest - more than %d facilities !\n", operation_tag, MAX_SUBCOMMANDS); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ return -1; ++ } ++ if (pri->debug & PRI_DEBUG_APDU) ++ { ++ pri_message(pri, "ROSE %i: Handle CcCcbsRequest\n", operation_tag); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ } ++ c_subcmd->cmd = CMD_CC_CCBSREQUEST_RR; ++ res = rose_ccbs_request_result_decode(pri, &c_subcmd->cc_ccbs_rr.cc_request_res, comp, len-i); ++ return res; ++ ++ case QSIG_CC_CCNRREQUEST: ++ c_subcmd = get_ptr_subcommand(&call->subcmds); ++ if (!c_subcmd) { ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "ROSE %i: return_result CcCcnrRequest - more than %d facilities !\n", operation_tag, MAX_SUBCOMMANDS); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ return -1; ++ } ++ if (pri->debug & PRI_DEBUG_APDU) ++ { ++ pri_message(pri, "ROSE %i: Handle CcCcnrRequest\n", operation_tag); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ } ++ c_subcmd->cmd = CMD_CC_CCNRREQUEST_RR; ++ res = rose_ccnr_request_result_decode(pri, &c_subcmd->cc_ccnr_rr.cc_request_res, comp, len-i); ++ return res; ++ ++ default: ++ if (pri->debug & PRI_DEBUG_APDU) { ++ pri_message(pri, "!! Unable to handle ROSE operation %d", operation_tag); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ } ++ return -1; ++ } + } else { + pri_message(pri, "Unable to handle return result on switchtype %d!\n", pri->switchtype); + return -1; +@@ -2414,6 +4210,7 @@ + int operation_tag; + unsigned char *vdata = data; + struct rose_component *comp = NULL, *invokeid = NULL, *operationid = NULL; ++ struct subcommand *c_subcmd; + + do { + /* Invoke ID stuff */ +@@ -2444,126 +4241,294 @@ + + if (pri->debug & PRI_DEBUG_APDU) + pri_message(pri, " [ Handling operation %d ]\n", operation_tag); +- switch (operation_tag) { +- case SS_CNID_CALLINGNAME: +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " Handle Name display operation\n"); +- return rose_calling_name_decode(pri, call, comp, len-i); +- case ROSE_CALL_TRANSFER_IDENTIFY: +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, "ROSE %i: CallTransferIdentify - not handled!\n", operation_tag); +- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); +- return -1; +- case ROSE_CALL_TRANSFER_ABANDON: +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, "ROSE %i: CallTransferAbandon - not handled!\n", operation_tag); +- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); +- return -1; +- case ROSE_CALL_TRANSFER_INITIATE: +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, "ROSE %i: CallTransferInitiate - not handled!\n", operation_tag); +- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); +- return -1; +- case ROSE_CALL_TRANSFER_SETUP: +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, "ROSE %i: CallTransferSetup - not handled!\n", operation_tag); +- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); +- return -1; +- case ROSE_CALL_TRANSFER_ACTIVE: +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, "ROSE %i: CallTransferActive - not handled!\n", operation_tag); +- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); +- return -1; +- case ROSE_CALL_TRANSFER_COMPLETE: +- if (pri->debug & PRI_DEBUG_APDU) +- { +- pri_message(pri, "ROSE %i: Handle CallTransferComplete\n", operation_tag); ++ ++ if (pri->switchtype == PRI_SWITCH_QSIG) { ++ ++ switch (operation_tag) { ++ case SS_CNID_CALLINGNAME: ++ if (pri->debug & PRI_DEBUG_APDU) { ++ pri_message(pri, "ROSE %i: Handle CallingName\n", operation_tag); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ } ++ return rose_calling_name_decode(pri, call, comp, len-i); ++ case SS_CNOP_CALLEDNAME: ++ if (pri->debug & PRI_DEBUG_APDU) { ++ pri_message(pri, "ROSE %i: Handle CalledName\n", operation_tag); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ } ++ return rose_called_name_decode(pri, call, comp, len-i); ++ case SS_CNOP_CONNECTEDNAME: ++ if (pri->debug & PRI_DEBUG_APDU) { ++ pri_message(pri, "ROSE %i: Handle ConnectedName\n", operation_tag); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ } ++ return rose_connected_name_decode(pri, call, comp, len-i); ++ case ROSE_CALL_TRANSFER_IDENTIFY: ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "ROSE %i: CallTransferIdentify - not handled!\n", operation_tag); + dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); +- } +- return rose_call_transfer_complete_decode(pri, call, comp, len-i); +- case ROSE_CALL_TRANSFER_UPDATE: +- if (pri->debug & PRI_DEBUG_APDU) +- { +- pri_message(pri, "ROSE %i: Handle CallTransferUpdate\n", operation_tag); ++ return -1; ++ case ROSE_CALL_TRANSFER_ABANDON: ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "ROSE %i: CallTransferAbandon - not handled!\n", operation_tag); + dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); +- } +- return rose_call_transfer_update_decode(pri, call, comp, len-i); +- case ROSE_SUBADDRESS_TRANSFER: +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, "ROSE %i: SubaddressTransfer - not handled!\n", operation_tag); +- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); +- return -1; +- case ROSE_DIVERTING_LEG_INFORMATION2: +- if (pri->debug & PRI_DEBUG_APDU) { +- pri_message(pri, "ROSE %i: Handle CallingName\n", operation_tag); +- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); +- } +- return rose_diverting_leg_information2_decode(pri, call, comp, len-i); +- case ROSE_AOC_NO_CHARGING_INFO_AVAILABLE: +- if (pri->debug & PRI_DEBUG_APDU) { +- pri_message(pri, "ROSE %i: AOC No Charging Info Available - not handled!", operation_tag); +- dump_apdu (pri, 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(pri, "ROSE %i: AOC-S Currency - not handled!", operation_tag); ++ return -1; ++ case ROSE_CALL_TRANSFER_INITIATE: ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "ROSE %i: CallTransferInitiate - not handled!\n", operation_tag); + dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); +- } +- return -1; +- case ROSE_AOC_AOCS_SPECIAL_ARR: +- if (pri->debug & PRI_DEBUG_APDU) { +- pri_message(pri, "ROSE %i: AOC-S Special Array - not handled!", operation_tag); ++ return -1; ++ case ROSE_CALL_TRANSFER_SETUP: ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "ROSE %i: CallTransferSetup - not handled!\n", operation_tag); + dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); +- } +- return -1; +- case ROSE_AOC_AOCD_CURRENCY: +- if (pri->debug & PRI_DEBUG_APDU) { +- pri_message(pri, "ROSE %i: AOC-D Currency - not handled!", operation_tag); ++ return -1; ++ case ROSE_CALL_TRANSFER_ACTIVE: ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "ROSE %i: Handle CallTransferActive\n", operation_tag); + dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); +- } +- return -1; +- case ROSE_AOC_AOCD_CHARGING_UNIT: +- if (pri->debug & PRI_DEBUG_APDU) { +- pri_message(pri, "ROSE %i: AOC-D Charging Unit - not handled!", operation_tag); ++ return rose_call_transfer_active_decode(pri, call, comp, len-i); ++ case ROSE_CALL_TRANSFER_COMPLETE: ++ if (pri->debug & PRI_DEBUG_APDU) ++ { ++ pri_message(pri, "ROSE %i: Handle CallTransferComplete\n", operation_tag); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ } ++ return rose_call_transfer_complete_decode(pri, call, comp, len-i); ++ case ROSE_CALL_TRANSFER_UPDATE: ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "ROSE %i: CallTransferUpdate - not handled!\n", operation_tag); + dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); +- } +- return -1; +- case ROSE_AOC_AOCE_CURRENCY: +- if (pri->debug & PRI_DEBUG_APDU) { +- pri_message(pri, "ROSE %i: AOC-E Currency - not handled!", operation_tag); ++ return -1; ++ case ROSE_SUBADDRESS_TRANSFER: ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "ROSE %i: SubaddressTransfer - not handled!\n", operation_tag); + dump_apdu (pri, (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 -1; ++ case ROSE_DIVERTING_LEG_INFORMATION1: ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " Handle DivertingLegInformation1\n"); ++ return rose_diverting_leg_information1_decode(pri, call, comp, len-i); ++ case ROSE_DIVERTING_LEG_INFORMATION2: ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " Handle DivertingLegInformation2\n"); ++ return rose_diverting_leg_information2_decode(pri, call, comp, len-i); ++ case ROSE_DIVERTING_LEG_INFORMATION3: ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " Handle DivertingLegInformation3\n"); ++ return rose_diverting_leg_information3_decode(pri, call, comp, len-i); ++ case SS_ANFPR_PATHREPLACEMENT: ++ /* Clear Queue */ ++ res = pri_call_apdu_queue_cleanup(call->bridged_call); ++ if (res) { ++ pri_message(pri, "Could not Clear queue ADPU\n"); ++ return -1; ++ } ++ anfpr_pathreplacement_respond(pri, call, ie); ++ break; ++ case QSIG_CC_CCBSREQUEST: ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "ROSE %i: invoke CcbsRequest - not handled!\n", operation_tag); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ return -1; ++ case QSIG_CC_CCNRREQUEST: ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "ROSE %i: invoke CcnrRequest - not handled!\n", operation_tag); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ return -1; ++ case QSIG_CC_CANCEL: ++ c_subcmd = get_ptr_subcommand(&call->subcmds); ++ if (!c_subcmd) { ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "ROSE %i: invoke CcCancel - more than %d facilities !\n", operation_tag, MAX_SUBCOMMANDS); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ return -1; ++ } ++ if (pri->debug & PRI_DEBUG_APDU) ++ { ++ pri_message(pri, "ROSE %i: Handle CcCancel\n", operation_tag); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ } ++ c_subcmd->cmd = CMD_CC_CANCEL_INV; ++ res = rose_cc_optional_arg_decode(pri, call, &c_subcmd->cc_cancel_inv.cc_optional_arg, comp, len-i); ++ return res; ++ case QSIG_CC_EXECPOSIBLE: ++ c_subcmd = get_ptr_subcommand(&call->subcmds); ++ if (!c_subcmd) { ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "ROSE %i: invoke CcExecposible - more than %d facilities !\n", operation_tag, MAX_SUBCOMMANDS); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ return -1; ++ } ++ if (pri->debug & PRI_DEBUG_APDU) ++ { ++ pri_message(pri, "ROSE %i: Handle CcExecposible\n", operation_tag); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ } ++ c_subcmd->cmd = CMD_CC_EXECPOSIBLE_INV; ++ res = rose_cc_optional_arg_decode(pri, call, &c_subcmd->cc_execposible_inv.cc_optional_arg, comp, len-i); ++ return res; ++ case QSIG_CC_PATHRESERVE: ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "ROSE %i: invoke CcPathreserve - not handled!\n", operation_tag); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ return -1; ++ case QSIG_CC_RINGOUT: ++ c_subcmd = get_ptr_subcommand(&call->subcmds); ++ if (!c_subcmd) { ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "ROSE %i: invoke CcRingout - more than %d facilities !\n", operation_tag, MAX_SUBCOMMANDS); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ return -1; ++ } ++ if (pri->debug & PRI_DEBUG_APDU) ++ { ++ pri_message(pri, "ROSE %i: Handle CcRingout\n", operation_tag); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ } ++ c_subcmd->cmd = CMD_CC_RINGOUT_INV; ++ res = rose_cc_ringout_inv_decode(pri, &c_subcmd->cc_ringout_inv.cc_extension, comp, len-i); ++ return res; ++ case QSIG_CC_SUSPEND: ++ if (pri->debug & PRI_DEBUG_APDU) ++ { ++ pri_message(pri, "ROSE %i: Handle CcSuspend\n", operation_tag); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ } + return 0; +- } +- case ROSE_AOC_IDENTIFICATION_OF_CHARGE: +- if (pri->debug & PRI_DEBUG_APDU) { +- pri_message(pri, "ROSE %i: AOC Identification Of Charge - not handled!", operation_tag); ++ case QSIG_CC_RESUME: ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "ROSE %i: invoke CcResume - not handled!\n", operation_tag); + dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ return -1; ++ default: ++ if (pri->debug & PRI_DEBUG_APDU) { ++ pri_message(pri, "!! Unable to handle ROSE operation %d", operation_tag); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ } ++ return -1; + } +- return -1; +- case SS_ANFPR_PATHREPLACEMENT: +- /* Clear Queue */ +- res = pri_call_apdu_queue_cleanup(call->bridged_call); +- if (res) { +- pri_message(pri, "Could not Clear queue ADPU\n"); +- return -1; +- } +- anfpr_pathreplacement_respond(pri, call, ie); +- break; +- default: +- if (pri->debug & PRI_DEBUG_APDU) { +- pri_message(pri, "!! Unable to handle ROSE operation %d", operation_tag); ++ } else { /* pri->switchtype == PRI_SWITCH_QSIG */ ++ ++ switch (operation_tag) { ++ case SS_CNID_CALLINGNAME: ++ if (pri->debug & PRI_DEBUG_APDU) { ++ pri_message(pri, "ROSE %i: Handle CallingName\n", operation_tag); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ } ++ return rose_calling_name_decode(pri, call, comp, len-i); ++ case ROSE_CALL_TRANSFER_IDENTIFY: ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "ROSE %i: CallTransferIdentify - not handled!\n", operation_tag); + dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ return -1; ++ case ROSE_CALL_TRANSFER_ABANDON: ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "ROSE %i: CallTransferAbandon - not handled!\n", operation_tag); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ return -1; ++ case ROSE_CALL_TRANSFER_INITIATE: ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "ROSE %i: CallTransferInitiate - not handled!\n", operation_tag); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ return -1; ++ case ROSE_CALL_TRANSFER_SETUP: ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "ROSE %i: CallTransferSetup - not handled!\n", operation_tag); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ return -1; ++ case ROSE_CALL_TRANSFER_ACTIVE: ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "ROSE %i: Handle CallTransferActive\n", operation_tag); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ return rose_call_transfer_active_decode(pri, call, comp, len-i); ++ case ROSE_CALL_TRANSFER_COMPLETE: ++ if (pri->debug & PRI_DEBUG_APDU) ++ { ++ pri_message(pri, "ROSE %i: Handle CallTransferComplete\n", operation_tag); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ } ++ return rose_call_transfer_complete_decode(pri, call, comp, len-i); ++ case ROSE_CALL_TRANSFER_UPDATE: ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "ROSE %i: CallTransferUpdate - not handled!\n", operation_tag); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ return -1; ++ case ROSE_SUBADDRESS_TRANSFER: ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "ROSE %i: SubaddressTransfer - not handled!\n", operation_tag); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ return -1; ++ case ROSE_DIVERTING_LEG_INFORMATION2: ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, " Handle DivertingLegInformation2\n"); ++ return rose_diverting_leg_information2_decode(pri, call, comp, len-i); ++ case ROSE_AOC_NO_CHARGING_INFO_AVAILABLE: ++ if (pri->debug & PRI_DEBUG_APDU) { ++ pri_message(pri, "ROSE %i: AOC No Charging Info Available - not handled!", operation_tag); ++ dump_apdu (pri, 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(pri, "ROSE %i: AOC-S Currency - not handled!", operation_tag); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ } ++ return -1; ++ case ROSE_AOC_AOCS_SPECIAL_ARR: ++ if (pri->debug & PRI_DEBUG_APDU) { ++ pri_message(pri, "ROSE %i: AOC-S Special Array - not handled!", operation_tag); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ } ++ return -1; ++ case ROSE_AOC_AOCD_CURRENCY: ++ if (pri->debug & PRI_DEBUG_APDU) { ++ pri_message(pri, "ROSE %i: AOC-D Currency - not handled!", operation_tag); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ } ++ return -1; ++ case ROSE_AOC_AOCD_CHARGING_UNIT: ++ if (pri->debug & PRI_DEBUG_APDU) { ++ pri_message(pri, "ROSE %i: AOC-D Charging Unit - not handled!", operation_tag); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ } ++ return -1; ++ case ROSE_AOC_AOCE_CURRENCY: ++ if (pri->debug & PRI_DEBUG_APDU) { ++ pri_message(pri, "ROSE %i: AOC-E Currency - not handled!", operation_tag); ++ dump_apdu (pri, (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(pri, "ROSE %i: AOC Identification Of Charge - not handled!", operation_tag); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ } ++ return -1; ++ case SS_ANFPR_PATHREPLACEMENT: ++ /* Clear Queue */ ++ res = pri_call_apdu_queue_cleanup(call->bridged_call); ++ if (res) { ++ pri_message(pri, "Could not Clear queue ADPU\n"); ++ return -1; ++ } ++ anfpr_pathreplacement_respond(pri, call, ie); ++ break; ++ default: ++ if (pri->debug & PRI_DEBUG_APDU) { ++ pri_message(pri, "!! Unable to handle ROSE operation %d", operation_tag); ++ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ } ++ return -1; + } +- return -1; + } + } while(0); + +@@ -2619,15 +4584,119 @@ + return 0; + } + ++/* ===== Begin Call Completion Supplementary Service (ETS 300 366/ECMA 186) ===== */ ++/* operationId e.g. QSIG_CC_CCBS_REQUEST and QSIG_CC_CCNR_REQUEST */ ++static int add_qsigCcRequestArg_facility_ie (struct pri *pri, q931_call *c) ++{ ++ int size = 0; ++ int i = 0; ++ unsigned char buffer[256]; ++ struct rose_component *comp = NULL, *compstk[10]; ++ int compsp = 0; ++ u_int8_t operationId = c->ccoperation; ++ char *numberA = c->callernum; ++ char *numberB = c->callednum; ++ ++ /* 1 Byte 0x80 | 0x1F = 9F Protocol Profile (0x93 wäre altes QSIG oder DDS1) */ ++ buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS); ++ ++ /* Interpretation component */ ++ ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i); /* 2. Byte NEtwork Facility Extension 0xAA = ASN1_CONTEXT_SPECIFIC(0x80) | (ASN1_CONSTRUCTOR 0x20) 0x0A (Tag laut Standard) */ ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0); /* (0x80, 0x01(len), 0x00) endPTNX */ ++ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0); /* (0x82, 0x01(len), 0x00) endPTNX */ ++ ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++ ++#if 0 ++ ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0); /* 0x8B, 0x01(len), 0x00 discard */ ++#endif ++ ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i); /* 0xA1, 0xXX (len of Invoke Sequenz) invoke APDU */ ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* Invoke ID */ ++ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri)); /* InvokeID 0x02 0x01 0xXX */ ++ ++ /*CcbsRequest ::= 40 or CcnrRequest ::= 27 */ ++ /* Operation ID: CCBS/CCNR */ ++ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, operationId); /* 0x02 0x01 0x28/0x1b */ ++ ++ /* ccbs/ccnr request argument */ ++ /* PresentedNumberUnscreened */ ++ ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i); /*0x30 0xXX (len)*/ ++ ASN1_PUSH(compstk, compsp, comp); ++ /* (0xA0, 0x01(len)) presentationAlloweAddress [0] PartyNumber */ ++ /* (0xA1, 0xXX (len) publicPartyNumber [1] IMPLICIT PublicPartyNumber */ ++ /* (0x0A, 0x01, 0x00 ) type of public party number = subscriber number */ ++ /* (0x12, 0xXX (len), 0xXX .. 0xXX) numeric string */ ++ size = rose_presented_number_unscreened_encode(pri, &buffer[i], PRES_ALLOWED, Q932_TON_UNKNOWN, numberA); ++ if (size < 0) ++ return -1; ++ i += size; ++ ++ /* (0xA1, 0xXX (len) [1] IMPLICIT PublicPartyNumber */ ++ ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ /* (0x0A, 0x01, 0x00 ) type of public party number = subscriber number */ ++ /* (0x12, 0xXX (len), 0xXX .. 0xXX) numeric string */ ++ size = rose_public_party_number_encode(pri, comp->data, 1, Q932_TON_UNKNOWN, numberB); ++ if (size < 0) ++ return -1; ++ i += size; ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++ ++ /* (0x40, 0xXX (len), 0xXX .. 0xXX) pSS1InfoElement */ ++ ASN1_ADD_SIMPLE(comp, (ASN1_APPLICATION | ASN1_TAG_0 ), buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ buffer[i++] = (0x04); /* add Bearer Capability IE */ ++ buffer[i++] = (0x03); /* len*/ ++ buffer[i++] = (0x80); /* ETSI Standard, Speech */ ++ buffer[i++] = (0x90); /* circuit mode, 64kbit/s */ ++ buffer[i++] = (0xa3); /* level1 protocol, a-law */ ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++#if 0 ++ /* can-retain-service [12] IMPLICIT BOOLEAN DEFAULT FALSE,*/ ++ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_12), buffer, i, 0); /* 0x1C, 0x01(len), 0x00 false */ ++#endif ++ /* retain-sig-connection [13] IMPLICIT BOOLEAN OPTIONAL, --TRUE: sign. connection to be retained */ ++ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_13), buffer, i, 1); /* 0x1D, 0x01(len), 0x01 true */ ++ ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++ ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++ ++ if (pri_call_apdu_queue(c, Q931_SETUP, buffer, i, NULL, NULL)) ++ return -1; ++ ++ return 0; ++} ++/* ===== End Call Completion Supplementary Service (ETS 300 366/ECMA 186) ===== */ ++ + int pri_call_add_standard_apdus(struct pri *pri, q931_call *call) + { + if (!pri->sendfacility) + return 0; + + if (pri->switchtype == PRI_SWITCH_QSIG) { /* For Q.SIG it does network and cpe operations */ +- if (call->redirectingnum[0]) ++ if (call->redirectingnum[0]) + rose_diverting_leg_information2_encode(pri, call); + add_callername_facility_ies(pri, call, 1); ++ if (call->ccoperation) { ++ switch(call->ccoperation) { ++ case 0: ++ break; ++ case QSIG_CC_CCBSREQUEST: ++ case QSIG_CC_CCNRREQUEST: ++ add_qsigCcRequestArg_facility_ie(pri, call); ++ break; ++ case QSIG_CC_RINGOUT: ++ add_qsigCcInv_facility_ie(pri, call, Q931_SETUP); ++ break; ++ default: ++ break; ++ } ++ } + return 0; + } + +@@ -2665,3 +4734,26 @@ + return 0; + } + ++int qsig_initiate_diverting_leg_information1(struct pri *pri, q931_call *call) ++{ ++ rose_diverting_leg_information1_encode(pri, call); ++ ++ if (q931_facility(pri, call)) { ++ pri_message(pri, "Could not schedule facility message for divertingLegInfo1\n"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++int qsig_initiate_call_transfer_complete(struct pri *pri, q931_call *call, int call_status) ++{ ++ rose_call_transfer_complete_encode(pri, call, call_status); ++ ++ if (q931_facility(pri, call)) { ++ pri_message(pri, "Could not schedule facility message for callTransferComplete\n"); ++ return -1; ++ } ++ ++ return 0; ++} +Index: pri_timers.h +=================================================================== +--- a/pri_timers.h (.../tags/1.4.9) (revision 700) ++++ b/pri_timers.h (.../team/group/issue14292) (revision 700) +@@ -62,6 +62,7 @@ + -1, /* T322 */ \ + 2500, /* TM20 - Q.921 Appendix IV */ \ + 3, /* NM20 - Q.921 Appendix IV */ \ ++ 45*60*1000 /* CC-Timer2 45 min */\ + } + + /* XXX Only our default timers are setup now XXX */ +Index: pri_facility.h +=================================================================== +--- a/pri_facility.h (.../tags/1.4.9) (revision 700) ++++ b/pri_facility.h (.../team/group/issue14292) (revision 700) +@@ -38,14 +38,6 @@ + #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_PRESENTATION_ALLOWED_EXTENDED 0xA1 +-#define ROSE_NAME_PRESENTATION_RESTRICTED_SIMPLE 0xA2 +-#define ROSE_NAME_PRESENTATION_RESTRICTED_EXTENDED 0xA3 +-#define ROSE_NAME_NOT_AVAIL 0x84 +- + /* Component types */ + #define COMP_TYPE_INTERPRETATION 0x8B + #define COMP_TYPE_NETWORK_PROTOCOL_PROFILE 0x92 +@@ -65,10 +57,11 @@ + #define ROSE_CALL_TRANSFER_COMPLETE 12 + #define ROSE_CALL_TRANSFER_UPDATE 13 + #define ROSE_SUBADDRESS_TRANSFER 14 ++#define QSIG_CF_CALLREROUTING 19 + /* Q.952 ROSE operations (Diverting) */ +-#define ROSE_DIVERTING_LEG_INFORMATION1 18 +-#define ROSE_DIVERTING_LEG_INFORMATION2 0x15 +-#define ROSE_DIVERTING_LEG_INFORMATION3 19 ++#define ROSE_DIVERTING_LEG_INFORMATION1 20 ++#define ROSE_DIVERTING_LEG_INFORMATION2 21 ++#define ROSE_DIVERTING_LEG_INFORMATION3 22 + /* Q.956 ROSE operations (Advice Of Charge) */ + #define ROSE_AOC_NO_CHARGING_INFO_AVAILABLE 26 + #define ROSE_AOC_CHARGING_REQUEST 30 +@@ -81,12 +74,27 @@ + #define ROSE_AOC_IDENTIFICATION_OF_CHARGE 37 + /* Q.SIG operations */ + #define SS_CNID_CALLINGNAME 0 ++#define SS_CNOP_CALLEDNAME 1 ++#define SS_CNOP_CONNECTEDNAME 2 + #define SS_ANFPR_PATHREPLACEMENT 4 +-#define SS_DIVERTING_LEG_INFORMATION2 21 + #define SS_MWI_ACTIVATE 80 + #define SS_MWI_DEACTIVATE 81 + #define SS_MWI_INTERROGATE 82 + ++/* ECMA 186 */ ++#define QSIG_CC_CCNRREQUEST PRI_CC_CCNRREQUEST /* 27 */ ++#define QSIG_CC_CANCEL PRI_CC_CANCEL /* 28 */ ++#define QSIG_CC_EXECPOSIBLE 29 ++#define QSIG_CC_PATHRESERVE 30 ++#define QSIG_CC_RINGOUT 31 ++#define QSIG_CC_SUSPEND 32 ++#define QSIG_CC_RESUME 33 ++#define QSIG_CC_CCBSREQUEST PRI_CC_CCBSREQUEST /* 40 */ ++ ++#define QSIG_CC_UNSPECIFIED 1008 ++#define QSIG_CC_REMOTE_USER_BUSY_AGAIN 1012 ++#define QSIG_CC_FAILURE_TO_MATCH 1013 ++ + /* ROSE definitions and data structures */ + #define INVOKE_IDENTIFIER 0x02 + #define INVOKE_LINKED_IDENTIFIER 0x80 +@@ -128,6 +136,12 @@ + #define ASN1_TAG_7 0x07 + #define ASN1_TAG_8 0x08 + #define ASN1_TAG_9 0x09 ++#define ASN1_TAG_10 0x0a ++#define ASN1_TAG_11 0x0b ++#define ASN1_TAG_12 0x0c ++#define ASN1_TAG_13 0x0d ++#define ASN1_TAG_14 0x0e ++#define ASN1_TAG_15 0x0f + + /* ASN.1 Identifier Octet - Primitive/Constructor Bit */ + #define ASN1_PC_MASK 0x20 +@@ -169,6 +183,20 @@ + #define Q932_TON_SUBSCRIBER 0x04 + #define Q932_TON_ABBREVIATED 0x06 + ++/* Q.SIG Character Sets. Listed in ISO/IEC 8859 */ ++#define CHARACTER_SET_UNKNOWN 0x00 ++#define CHARACTER_SET_ISO8859_1 0x01 ++#define CHARACTER_SET_ISO8859_2 0x03 ++#define CHARACTER_SET_ISO8859_3 0x04 ++#define CHARACTER_SET_ISO8859_4 0x05 ++#define CHARACTER_SET_ISO8859_5 0x06 ++#define CHARACTER_SET_ISO8859_7 0x07 ++ ++/* Q.SIG Subscription Option. Listed in ECMA-174 */ ++#define QSIG_NO_NOTIFICATION 0x00 ++#define QSIG_NOTIFICATION_WITHOUT_DIVERTED_TO_NR 0x01 ++#define QSIG_NOTIFICATION_WITH_DIVERTED_TO_NR 0x02 ++ + /* RLT related Operations */ + #define RLT_SERVICE_ID 0x3e + #define RLT_OPERATION_IND 0x01 +@@ -314,6 +342,18 @@ + /* starts a QSIG Path Replacement */ + int anfpr_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2); + ++int qsig_initiate_diverting_leg_information1(struct pri *pri, q931_call *call); ++ ++int qsig_initiate_call_transfer_complete(struct pri *pri, q931_call *call, int call_status); ++ ++int rose_diverting_leg_information1_encode(struct pri *pri, q931_call *call); ++ ++int rose_diverting_leg_information3_encode(struct pri *pri, q931_call *call, int messagetype); ++ ++int rose_connected_name_encode(struct pri *pri, q931_call *call, int messagetype); ++ ++int rose_called_name_encode(struct pri *pri, q931_call *call, int messagetype); ++ + /* Use this function to queue a facility-IE born APDU onto a call + * call is the call to use, messagetype is any one of the Q931 messages, + * apdu is the apdu data, apdu_len is the length of the apdu data */ +@@ -325,6 +365,8 @@ + /* Adds the "standard" APDUs to a call */ + int pri_call_add_standard_apdus(struct pri *pri, q931_call *call); + ++int add_qsigCcInv_facility_ie (struct pri *pri, q931_call *c, int messagetype); ++ + int asn1_dump(struct pri *pri, void *comp, int len); + + #endif /* _PRI_FACILITY_H */ +Index: libpri.h +=================================================================== +--- a/libpri.h (.../tags/1.4.9) (revision 700) ++++ b/libpri.h (.../team/group/issue14292) (revision 700) +@@ -81,6 +81,7 @@ + #define PRI_EVENT_NOTIFY 16 /* Notification received */ + #define PRI_EVENT_PROGRESS 17 /* When we get CALL_PROCEEDING or PROGRESS */ + #define PRI_EVENT_KEYPAD_DIGIT 18 /* When we receive during ACTIVE state */ ++#define PRI_EVENT_FACILITY 19 /* Facility received */ + + /* Simple states */ + #define PRI_STATE_DOWN 0 +@@ -135,16 +136,45 @@ + #define PRI_UNKNOWN 0x0 + + /* Presentation */ +-#define PRES_ALLOWED_USER_NUMBER_NOT_SCREENED 0x00 +-#define PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN 0x01 +-#define PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN 0x02 +-#define PRES_ALLOWED_NETWORK_NUMBER 0x03 +-#define PRES_PROHIB_USER_NUMBER_NOT_SCREENED 0x20 +-#define PRES_PROHIB_USER_NUMBER_PASSED_SCREEN 0x21 +-#define PRES_PROHIB_USER_NUMBER_FAILED_SCREEN 0x22 +-#define PRES_PROHIB_NETWORK_NUMBER 0x23 +-#define PRES_NUMBER_NOT_AVAILABLE 0x43 ++#define PRES_NUMBER_TYPE 0x03 ++#define PRES_USER_NUMBER_UNSCREENED 0x00 ++#define PRES_USER_NUMBER_PASSED_SCREEN 0x01 ++#define PRES_USER_NUMBER_FAILED_SCREEN 0x02 ++#define PRES_NETWORK_NUMBER 0x03 + ++#define PRES_RESTRICTION 0x60 ++#define PRES_ALLOWED 0x00 ++#define PRES_RESTRICTED 0x20 ++#define PRES_UNAVAILABLE 0x40 ++#define PRES_RESERVED 0x60 ++ ++#define PRES_ALLOWED_USER_NUMBER_NOT_SCREENED \ ++ (PRES_ALLOWED | PRES_USER_NUMBER_UNSCREENED) ++ ++#define PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN \ ++ (PRES_ALLOWED | PRES_USER_NUMBER_PASSED_SCREEN) ++ ++#define PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN \ ++ (PRES_ALLOWED | PRES_USER_NUMBER_FAILED_SCREEN) ++ ++#define PRES_ALLOWED_NETWORK_NUMBER \ ++ (PRES_ALLOWED | PRES_NETWORK_NUMBER) ++ ++#define PRES_PROHIB_USER_NUMBER_NOT_SCREENED \ ++ (PRES_RESTRICTED | PRES_USER_NUMBER_UNSCREENED) ++ ++#define PRES_PROHIB_USER_NUMBER_PASSED_SCREEN \ ++ (PRES_RESTRICTED | PRES_USER_NUMBER_PASSED_SCREEN) ++ ++#define PRES_PROHIB_USER_NUMBER_FAILED_SCREEN \ ++ (PRES_RESTRICTED | PRES_USER_NUMBER_FAILED_SCREEN) ++ ++#define PRES_PROHIB_NETWORK_NUMBER \ ++ (PRES_RESTRICTED | PRES_NETWORK_NUMBER) ++ ++#define PRES_NUMBER_NOT_AVAILABLE \ ++ (PRES_UNAVAILABLE | PRES_NETWORK_NUMBER) ++ + /* Causes for disconnection */ + #define PRI_CAUSE_UNALLOCATED 1 + #define PRI_CAUSE_NO_ROUTE_TRANSIT_NET 2 /* !Q.SIG */ +@@ -303,8 +333,141 @@ + #define PRI_NSF_ATT_MULTIQUEST 0xF0 + #define PRI_NSF_CALL_REDIRECTION_SERVICE 0xF7 + ++/* ECMA 186 */ ++#define PRI_CC_CCNRREQUEST 27 ++#define PRI_CC_CANCEL 28 ++#define PRI_CC_CCBSREQUEST 40 ++ + typedef struct q931_call q931_call; + ++/* Connected line update source code */ ++enum PRI_CONNECTED_LINE_UPDATE_SOURCE { ++ PRI_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN, /* Update for unknown reason (May be interpreted to mean from answer) */ ++ PRI_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, /* Update from normal call answering */ ++ PRI_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER, /* Update from call transfer(active) (Party has already answered) */ ++ PRI_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING /* Update from call transfer(alerting) (Party has not answered yet) */ ++}; ++ ++/* Information needed to identify an endpoint in a call. */ ++struct pri_party_id { ++ char number[256]; /* Subscriber phone number */ ++ char name[256]; /* Subscriber name */ ++ int number_type; /* Q.931 encoded "type of number" and "numbering plan identification" */ ++ int number_presentation; /* Q.931 encoded "presentation indicator" and "screening indicator" */ ++}; ++ ++/* Connected Line/Party information */ ++struct pri_party_connected_line { ++ struct pri_party_id id; /* Connected party ID */ ++ int source; /* Information about the source of an update . ++ * enum PRI_CONNECTED_LINE_UPDATE_SOURCE values ++ * for Normal-Answer, Call-transfer */ ++}; ++ ++/* Redirecting Line information. ++ * RDNIS (Redirecting Directory Number Information Service) ++ * Where a call diversion or transfer was invoked. */ ++struct pri_party_redirecting { ++ struct pri_party_id from; /* Who is redirecting the call (Sent to the party the call is redirected toward) */ ++ struct pri_party_id to; /* Call is redirecting to a new party (Sent to the caller) */ ++ int count; /* Number of times the call was redirected */ ++ int reason; /* Redirection reasons */ ++}; ++ ++/* Structures for qsig_cc_facilities */ ++struct qsig_cc_extension { ++ int cc_extension_tag; ++ char extension[256]; ++}; ++ ++struct qsig_cc_optional_arg { ++ char number_A[256]; ++ char number_B[256]; ++ int service; ++ struct qsig_cc_extension cc_extension; ++}; ++ ++struct qsig_cc_request_res { ++ int no_path_reservation; ++ int retain_service; ++ struct qsig_cc_extension cc_extension; ++}; ++ ++/* Command derived from Facility */ ++#define CMD_REDIRECTING 1 ++#define CMD_CONNECTEDLINE 2 ++#define CMD_CC_CCBSREQUEST_RR 3 ++#define CMD_CC_CCNRREQUEST_RR 4 ++#define CMD_CC_CANCEL_INV 5 ++#define CMD_CC_EXECPOSIBLE_INV 6 ++#define CMD_CC_RINGOUT_INV 7 ++#define CMD_CC_SUSPEND_INV 8 ++#define CMD_CC_ERROR 9 ++ ++#define CCERROR_UNSPECIFIED 1008 ++#define CCERROR_REMOTE_USER_BUSY_AGAIN 1012 ++#define CCERROR_FAILURE_TO_MATCH 1013 ++ ++struct cmd_connectedline { ++ struct pri_party_connected_line connected; ++}; ++ ++struct cmd_redirecting { ++ struct pri_party_redirecting redirecting; ++}; ++ ++struct cmd_cc_ccbs_rr { ++ struct qsig_cc_request_res cc_request_res; ++}; ++ ++struct cmd_cc_ccnr_rr { ++ struct qsig_cc_request_res cc_request_res; ++}; ++ ++struct cmd_cc_cancel_inv { ++ struct qsig_cc_optional_arg cc_optional_arg; ++}; ++ ++struct cmd_cc_execposible_inv { ++ struct qsig_cc_optional_arg cc_optional_arg; ++}; ++ ++struct cmd_cc_suspend_inv { ++ struct qsig_cc_extension cc_extension; ++}; ++ ++struct cmd_cc_ringout_inv { ++ struct qsig_cc_extension cc_extension; ++}; ++ ++struct cmd_cc_error { ++ int error_value; ++}; ++ ++struct subcommand { ++ int cmd; ++ union { ++ struct cmd_connectedline connectedline; ++ struct cmd_redirecting redirecting; ++ struct cmd_cc_ccbs_rr cc_ccbs_rr; ++ struct cmd_cc_ccnr_rr cc_ccnr_rr; ++ struct cmd_cc_cancel_inv cc_cancel_inv; ++ struct cmd_cc_execposible_inv cc_execposible_inv; ++ struct cmd_cc_suspend_inv cc_suspend_inv; ++ struct cmd_cc_ringout_inv cc_ringout_inv; ++ struct cmd_cc_error cc_error; ++ }; ++}; ++ ++/* Max number of subcommands per event message */ ++#define MAX_SUBCOMMANDS 4 ++ ++struct subcommands { ++ int counter_subcmd; ++ struct subcommand subcmd[MAX_SUBCOMMANDS]; ++}; ++ ++ + typedef struct pri_event_generic { + /* Events with no additional information fall in this category */ + int e; +@@ -328,6 +491,11 @@ + int progressmask; + q931_call *call; + char useruserinfo[260]; /* User->User info */ ++ char calledname[256]; ++ char callednum[256]; ++ int calledpres; ++ int calledplan; ++ struct subcommands subcmds; + } pri_event_ringing; + + typedef struct pri_event_answer { +@@ -338,6 +506,12 @@ + int progressmask; + q931_call *call; + char useruserinfo[260]; /* User->User info */ ++ char connectednum[256]; ++ char connectedname[256]; ++ int connectedpres; ++ int connectedplan; ++ int source; ++ struct subcommands subcmds; + } pri_event_answer; + + typedef struct pri_event_facname { +@@ -351,6 +525,14 @@ + int callingplan; /* Dialing plan of Calling entity */ + } pri_event_facname; + ++struct pri_event_facility { ++ int e; ++ int channel; ++ int cref; ++ q931_call *call; ++ struct subcommands subcmds; ++}; ++ + #define PRI_CALLINGPLANANI + #define PRI_CALLINGPLANRDNIS + typedef struct pri_event_ring { +@@ -383,6 +565,9 @@ + char origcallednum[256]; + int callingplanorigcalled; /* Dialing plan of Originally Called Number */ + int origredirectingreason; ++ int redirectingpres; ++ int redirectingcount; ++ struct subcommands subcmds; + } pri_event_ring; + + typedef struct pri_event_hangup { +@@ -393,6 +578,7 @@ + q931_call *call; /* Opaque call pointer */ + long aoc_units; /* Advise of Charge number of charged units */ + char useruserinfo[260]; /* User->User info */ ++ struct subcommands subcmds; + } pri_event_hangup; + + typedef struct pri_event_restart_ack { +@@ -445,6 +631,7 @@ + pri_event_setup_ack setup_ack; /* SETUP_ACKNOWLEDGE structure */ + pri_event_notify notify; /* Notification */ + pri_event_keypad_digit digit; /* Digits that come during a call */ ++ struct pri_event_facility facility; + } pri_event; + + struct pri; +@@ -531,6 +718,12 @@ + Set non-isdn to non-zero if you are not connecting to ISDN equipment */ + int pri_answer(struct pri *pri, q931_call *call, int channel, int nonisdn); + ++/* Give connected line information to a call */ ++int pri_connected_line_update(struct pri *pri, q931_call *call, struct pri_party_connected_line *connected); ++ ++/* Give redirection information to a call */ ++int pri_redirecting_update(struct pri *pri, q931_call *call, struct pri_party_redirecting *redirecting); ++ + /* Set CRV reference for GR-303 calls */ + + +@@ -558,7 +751,12 @@ + + /* Create a new call */ + q931_call *pri_new_call(struct pri *pri); ++q931_call *pri_new_nochannel_call(struct pri *pri, int *cr); + ++q931_call *pri_find_call(struct pri *pri, int cr); ++ ++void pri_call_set_cc_operation(q931_call *call, int cc_operation); ++ + /* Retrieve CRV reference for GR-303 calls. Returns >0 on success. */ + int pri_get_crv(struct pri *pri, q931_call *call, int *callmode); + +@@ -584,6 +782,11 @@ + int pri_sr_set_called(struct pri_sr *sr, char *called, int calledplan, int complete); + int pri_sr_set_caller(struct pri_sr *sr, char *caller, char *callername, int callerplan, int callerpres); + int pri_sr_set_redirecting(struct pri_sr *sr, char *num, int plan, int pres, int reason); ++void pri_sr_set_redirecting_name(struct pri_sr *sr, char *name); ++ ++int pri_sr_set_ccringout(struct pri_sr *sr, int ccringout); ++int pri_sr_set_ccbsnr(struct pri_sr *sr, int ccbsnr); ++ + #define PRI_USER_USER_TX + /* Set the user user field. Warning! don't send binary data accross this field */ + void pri_sr_set_useruser(struct pri_sr *sr, const char *userchars); +@@ -595,7 +798,10 @@ + /* Set a call has a call indpendent signalling connection (i.e. no bchan) */ + int pri_sr_set_connection_call_independent(struct pri_sr *req); + +-/* Send an MWI indication to a remote location. If activate is non zero, activates, if zero, decativates */ ++/* Set a no channel call (i.e. QSIG-CCBS/CCNR) */ ++int pri_sr_set_no_channel_call(struct pri_sr *req); ++ ++/* Send an MWI indication to a remote location. If activate is non zero, activates, if zero, deactivates */ + int pri_mwi_activate(struct pri *pri, q931_call *c, char *caller, int callerplan, char *callername, int callerpres, char *called, int calledplan); + + /* Send an MWI deactivate request to a remote location */ +@@ -698,6 +904,7 @@ + #define PRI_TIMER_TM20 28 /* maximum time avaiting XID response */ + #define PRI_TIMER_NM20 29 /* number of XID retransmits */ + ++#define PRI_TIMER_CCBST2 30 /* maximum time on completion of CC Call */ + /* Get PRI version */ + const char *pri_get_version(void); + +Index: pri.c +=================================================================== +--- a/pri.c (.../tags/1.4.9) (revision 700) ++++ b/pri.c (.../team/group/issue14292) (revision 700) +@@ -166,6 +166,8 @@ + return PRI_TIMER_T321; + else if (!strcasecmp(timer, "T322")) + return PRI_TIMER_T322; ++ else if (!strcasecmp(timer, "CCT2")) ++ return PRI_TIMER_CCBST2; + else + return -1; + } +@@ -348,6 +350,8 @@ + return "Restart ACK"; + case PRI_EVENT_FACNAME: + return "FacName"; ++ case PRI_EVENT_FACILITY: ++ return "Facility"; + case PRI_EVENT_INFO_RECEIVED: + return "Info Received"; + case PRI_EVENT_PROCEEDING: +@@ -551,6 +555,131 @@ + return q931_connect(pri, call, channel, nonisdn); + } + ++int pri_connected_line_update(struct pri *pri, q931_call *call, struct pri_party_connected_line *connected) ++{ ++ if (!pri || !call) ++ return -1; ++ ++ libpri_copy_string(call->connectednum, connected->id.number, sizeof(call->connectednum)); ++ libpri_copy_string(call->connectedname, connected->id.name, sizeof(call->connectedname)); ++ call->connectedplan = connected->id.number_type; ++ call->connectedpres = connected->id.number_presentation; ++ ++ if (pri->switchtype == PRI_SWITCH_QSIG) { ++ switch (call->ourcallstate) { ++ case Q931_CALL_STATE_ACTIVE: ++ /* immediately send callTransferComplete APDU, callStatus=answered(0) */ ++ qsig_initiate_call_transfer_complete(pri, call, 0); ++ break; ++ case Q931_CALL_STATE_OVERLAP_RECEIVING: ++ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING: ++ /* queue updates for next ALERTING */ ++ if (call->connectedname[0]) { ++ /* queue connectedName to be send with next Q931_ALERTING */ ++ rose_called_name_encode(pri, call, Q931_ALERTING); ++ } ++ ++ if (call->divertedstate != DIVERTEDSTATE_NONE) { ++ libpri_copy_string(call->divertedtonum, connected->id.number, sizeof(call->divertedtonum)); ++ libpri_copy_string(call->divertedtoname, connected->id.name, sizeof(call->divertedtoname)); ++ call->divertedtoplan = connected->id.number_type; ++ call->divertedtopres = connected->id.number_presentation; ++ ++ if ((call->divertedstate == DIVERTEDSTATE_DIVERTED) && call->divertedtonum[0]) { ++ /* immediately send divertingLegInformation1 APDU */ ++ qsig_initiate_diverting_leg_information1(pri, call); ++ call->divertedstate = DIVERTEDSTATE_DIVLEGINFO1SEND; ++ } ++ if ((call->divertedstate == DIVERTEDSTATE_DIVLEGINFO1SEND) && call->divertedtoname[0]) { ++ /* queue divertingLegInformation3 to be send with next Q931_ALERTING */ ++ rose_diverting_leg_information3_encode(pri, call, Q931_ALERTING); ++ call->divertedstate = DIVERTEDSTATE_DIVLEGINFO3SEND; ++ } ++ } ++ break; ++ case Q931_CALL_STATE_CALL_RECEIVED: ++ /* queue updates for next CONNECT */ ++ if (call->connectedname[0] && ((call->divertedstate == DIVERTEDSTATE_NONE) || (call->divertedstate == DIVERTEDSTATE_DIVLEGINFO3SEND))) { ++ /* queue connectedName to be send with next Q931_CONNECT */ ++ rose_connected_name_encode(pri, call, Q931_CONNECT); ++ } ++ ++ if (call->divertedstate != DIVERTEDSTATE_NONE) { ++ libpri_copy_string(call->divertedtonum, connected->id.number, sizeof(call->divertedtonum)); ++ libpri_copy_string(call->divertedtoname, connected->id.name, sizeof(call->divertedtoname)); ++ call->divertedtoplan = connected->id.number_type; ++ call->divertedtopres = connected->id.number_presentation; ++ ++ if ((call->divertedstate == DIVERTEDSTATE_DIVERTED) && call->divertedtonum[0]) { ++ /* queue divertingLegInformation1 to be send with next Q931_FACILITY */ ++ rose_diverting_leg_information1_encode(pri, call); ++ call->divertedstate = DIVERTEDSTATE_DIVLEGINFO1SEND; ++ ++ if (call->divertedtoname[0]) { ++ /* queue divertingLegInformation3 to be send with next Q931_FACILITY */ ++ rose_diverting_leg_information3_encode(pri, call, Q931_FACILITY); ++ call->divertedstate = DIVERTEDSTATE_DIVLEGINFO3SEND; ++ } ++ ++ /* immediately send Q931_FACILITY */ ++ if (q931_facility(pri, call)) { ++ pri_message(pri, "Could not schedule facility message for divertingLegInfo1+3\n"); ++ } ++ } ++ if ((call->divertedstate == DIVERTEDSTATE_DIVLEGINFO1SEND) && call->divertedtoname[0]) { ++ /* queue divertingLegInformation3 to be send with next Q931_CONNECT */ ++ rose_diverting_leg_information3_encode(pri, call, Q931_CONNECT); ++ call->divertedstate = DIVERTEDSTATE_DIVLEGINFO3SEND; ++ } ++ } ++ break; ++ } ++ } ++ ++ return 0; ++} ++ ++int pri_redirecting_update(struct pri *pri, q931_call *call, struct pri_party_redirecting *redirecting) ++{ ++ if (!pri || !call) ++ return -1; ++ ++ libpri_copy_string(call->divertedtonum, redirecting->to.number, sizeof(call->divertedtonum)); ++ libpri_copy_string(call->divertedtoname, redirecting->to.name, sizeof(call->divertedtoname)); ++ call->divertedtoplan = redirecting->to.number_type; ++ call->divertedtopres = redirecting->to.number_presentation; ++ call->divertedtoreason = redirecting->reason; ++ ++ if (pri->switchtype == PRI_SWITCH_QSIG) { ++ switch (call->ourcallstate) { ++ case Q931_CALL_STATE_ACTIVE: ++ /* immediately send callTransferComplete APDU, callStatus=alerting(1) */ ++ qsig_initiate_call_transfer_complete(pri, call, 1); ++ break; ++ case Q931_CALL_STATE_OVERLAP_RECEIVING: ++ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING: ++ call->divertedstate = DIVERTEDSTATE_DIVERTED; ++ ++ if (call->divertedtonum[0]) { ++ /* immediately send divertingLegInformation1 APDU */ ++ qsig_initiate_diverting_leg_information1(pri, call); ++ call->divertedstate = DIVERTEDSTATE_DIVLEGINFO1SEND; ++ } ++ if ((call->divertedstate == DIVERTEDSTATE_DIVLEGINFO1SEND) && call->divertedtoname[0]) { ++ /* queue divertingLegInformation3 to be send with next Q931_ALERTING */ ++ rose_diverting_leg_information3_encode(pri, call, Q931_ALERTING); ++ call->divertedstate = DIVERTEDSTATE_DIVLEGINFO3SEND; ++ } ++ break; ++ default: ++ pri_message(pri, "Redirecting update in state %d\n", call->ourcallstate); ++ break; ++ } ++ } ++ ++ return 0; ++} ++ + #if 0 + /* deprecated routines, use pri_hangup */ + int pri_release(struct pri *pri, q931_call *call, int cause) +@@ -637,6 +766,17 @@ + return q931_new_call(pri); + } + ++q931_call *pri_new_nochannel_call(struct pri *pri, int *cr) ++{ ++ q931_call *call; ++ if (!pri) ++ return NULL; ++ call = q931_new_call(pri); ++ if (cr) ++ *cr = call->cr; ++ return call; ++} ++ + void pri_dump_event(struct pri *pri, pri_event *e) + { + if (!pri || !e) +@@ -679,6 +819,15 @@ + return 0; + } + ++int pri_sr_set_no_channel_call(struct pri_sr *req) ++{ ++ if (!req) ++ return -1; ++ ++ req->nochannelsignalling = 1; ++ return 0; ++} ++ + /* Don't call any other pri functions on this */ + int pri_mwi_activate(struct pri *pri, q931_call *c, char *caller, int callerplan, char *callername, int callerpres, char *called, + int calledplan) +@@ -829,6 +978,10 @@ + struct q921_frame *f; + int q921outstanding = 0; + #endif ++ q931_call *cur, *prev; ++ struct pri *master; ++ int counter = 0; ++ + if (!pri) + return NULL; + +@@ -862,10 +1015,57 @@ + len += sprintf(buf + len, "T309 Timer: %d\n", pri->timers[PRI_TIMER_T309]); + len += sprintf(buf + len, "T313 Timer: %d\n", pri->timers[PRI_TIMER_T313]); + len += sprintf(buf + len, "N200 Counter: %d\n", pri->timers[PRI_TIMER_N200]); ++ len += sprintf(buf + len, "CCT2 Timer: %d\n", pri->timers[PRI_TIMER_CCBST2]); ++ /* Find the master - He has the call pool */ ++ if (pri->master) ++ master = pri->master; ++ else ++ master = pri; + ++ cur = *master->callpool; ++ prev = NULL; ++ while(cur) { ++ if (cur->cctimer2) { ++ struct timeval tv; ++ int time_ms_to_go, time_to_go_min, time_to_go_sec; ++ gettimeofday(&tv, NULL); ++ time_ms_to_go = (pri->pri_sched[cur->cctimer2].when.tv_sec - tv.tv_sec)*1000; ++ time_to_go_min = time_ms_to_go/1000/60; ++ time_to_go_sec = (time_ms_to_go-(time_to_go_min*60*1000))/1000; ++ ++ len += sprintf(buf + len, "%d. Active Q.931 Call: %p cr=%d: (%dmin %dsec)\n", ++ ++counter, cur, cur->cr, ++ time_to_go_min, time_to_go_sec); ++ } else { ++ len += sprintf(buf + len, "%d. Active Q.931 Call: %p cr=%d\n", ++counter, cur, cur->cr); ++ } ++ cur = cur->next; ++ } ++ + return strdup(buf); + } + ++q931_call *pri_find_call(struct pri *pri, int cr) ++{ ++ q931_call *cur; ++ struct pri *master; ++ ++ /* Find the master - He has the call pool */ ++ if (pri->master) ++ master = pri->master; ++ else ++ master = pri; ++ ++ cur = *master->callpool; ++ while(cur) { ++ if (cur->cr == cr) ++ return cur; ++ cur = cur->next; ++ } ++ ++ return NULL; ++} ++ + int pri_get_crv(struct pri *pri, q931_call *call, int *callmode) + { + return q931_call_getcrv(pri, call, callmode); +@@ -936,3 +1136,25 @@ + sr->redirectingreason = reason; + return 0; + } ++ ++void pri_sr_set_redirecting_name(struct pri_sr *sr, char *name) ++{ ++ sr->redirectingname = name; ++} ++ ++int pri_sr_set_ccringout(struct pri_sr *sr, int ccringout) ++{ ++ sr->ccringout = ccringout; ++ return 0; ++} ++ ++int pri_sr_set_ccbsnr(struct pri_sr *sr, int ccbsnr) ++{ ++ sr->ccbsnr = ccbsnr; ++ return 0; ++} ++ ++void pri_call_set_cc_operation(q931_call *call, int cc_operation) ++{ ++ call->ccoperation = cc_operation; ++} +Index: pri_internal.h +=================================================================== +--- a/pri_internal.h (.../tags/1.4.9) (revision 700) ++++ b/pri_internal.h (.../team/group/issue14292) (revision 700) +@@ -36,6 +36,12 @@ + #define DBGHEAD __FILE__ ":%d %s: " + #define DBGINFO __LINE__,__PRETTY_FUNCTION__ + ++/* divertedstate */ ++#define DIVERTEDSTATE_NONE 0 ++#define DIVERTEDSTATE_DIVERTED 1 ++#define DIVERTEDSTATE_DIVLEGINFO1SEND 2 ++#define DIVERTEDSTATE_DIVLEGINFO3SEND 3 ++ + struct pri_sched { + struct timeval when; + void (*callback)(void *data); +@@ -47,7 +53,7 @@ + enum q931_mode; + + /* No more than 128 scheduled events */ +-#define MAX_SCHED 128 ++#define MAX_SCHED 128+256 /* 256 ccT2 timer events*/ + + #define MAX_TIMERS 32 + +@@ -142,13 +148,17 @@ + int calledplan; + int userl1; + int numcomplete; ++ char *redirectingname; + char *redirectingnum; + int redirectingplan; + int redirectingpres; + int redirectingreason; + int justsignalling; ++ int nochannelsignalling; ++ int ccbsnr; + const char *useruserinfo; + int transferable; ++ int ccringout; + }; + + /* Internal switch types */ +@@ -202,6 +212,7 @@ + + int sentchannel; + int justsignalling; /* for a signalling-only connection */ ++ int nochannelsignalling; + + int progcode; /* Progress coding */ + int progloc; /* Progress Location */ +@@ -225,12 +236,19 @@ + char callernum[256]; + char callername[256]; + ++ int ccoperation; /* QSIG_CCBSREQUEST/QSIG_CCNRREQUEST */ ++ int ccrequestresult; ++ int cctimer2; /* Timer for QSIG-timer2 */ ++ /* QSIG cc infos (receive) */ ++ struct subcommands subcmds; ++ + char keypad_digits[64]; /* Buffer for digits that come in KEYPAD_FACILITY */ + + int ani2; /* ANI II */ + + int calledplan; + int nonisdn; ++ char calledname[256]; + char callednum[256]; /* Called Number */ + int complete; /* no more digits coming */ + int newcall; /* if the received message has a new call reference value */ +@@ -241,6 +259,7 @@ + int redirectingplan; + int redirectingpres; + int redirectingreason; ++ int redirectingcount; + char redirectingnum[256]; /* Number of redirecting party */ + char redirectingname[256]; /* Name of redirecting party */ + +@@ -251,6 +270,39 @@ + char origcalledname[256]; /* Original name of person being called */ + char origcallednum[256]; /* Orignal number of person being called */ + ++ int connectedplan; ++ int connectedpres; ++ char connectednum[256]; ++ char connectedname[256]; ++ ++ /* divertingLegInformation1 */ ++ int divleginfo1activeflag; ++ int divertedtoplan; ++ int divertedtopres; ++ int divertedtoreason; ++ char divertedtonum[256]; ++ int divertedtocount; ++ ++ /* divertingLegInformation3 */ ++ int divleginfo3activeflag; ++ char divertedtoname[256]; ++ int divertedstate; ++ ++ /* callTransferComplete */ ++ int ctcompleteflag; ++ int ctcompletepres; ++ int ctcompleteplan; ++ char ctcompletenum[256]; ++ char ctcompletename[256]; ++ int ctcompletecallstatus; ++ ++ /* callTransferActive */ ++ int ctactiveflag; ++ int ctactivepres; ++ int ctactiveplan; ++ char ctactivenum[256]; ++ char ctactivename[256]; ++ + int useruserprotocoldisc; + char useruserinfo[256]; + char callingsubaddr[256]; /* Calling parties sub address */ +Index: q921.c +=================================================================== +--- a/q921.c (.../tags/1.4.9) (revision 700) ++++ b/q921.c (.../team/group/issue14292) (revision 700) +@@ -268,12 +268,31 @@ + pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri); + } + ++static void q921_send_queued_iframes(struct pri *pri) ++{ ++ struct q921_frame *f; ++ ++ f = pri->txqueue; ++ while(f && (pri->windowlen < pri->window)) { ++ if (!f->transmitted) { ++ /* Send it now... */ ++ if (pri->debug & PRI_DEBUG_Q921_DUMP) ++ pri_message(pri, "-- Finally transmitting %d, since window opened up (%d)\n", f->h.n_s, pri->windowlen); ++ f->transmitted++; ++ pri->windowlen++; ++ f->h.n_r = pri->v_r; ++ f->h.p_f = 0; ++ q921_transmit(pri, (q921_h *)(&f->h), f->len); ++ } ++ f = f->next; ++ } ++} ++ + static pri_event *q921_ack_rx(struct pri *pri, int ack, int send_untransmitted_frames) + { + int x; + int cnt=0; + pri_event *ev; +- struct q921_frame *f; + /* Make sure the ACK was within our window */ + for (x=pri->v_a; (x != pri->v_s) && (x != ack); Q921_INC(x)); + if (x != ack) { +@@ -309,20 +328,7 @@ + if (!pri->busy && send_untransmitted_frames) { + pri->retrans = 0; + /* Search for something to send */ +- f = pri->txqueue; +- while(f && (pri->windowlen < pri->window)) { +- if (!f->transmitted) { +- /* Send it now... */ +- if (pri->debug & PRI_DEBUG_Q921_DUMP) +- pri_message(pri, "-- Finally transmitting %d, since window opened up (%d)\n", f->h.n_s, pri->windowlen); +- f->transmitted++; +- pri->windowlen++; +- f->h.n_r = pri->v_r; +- f->h.p_f = 0; +- q921_transmit(pri, (q921_h *)(&f->h), f->len); +- } +- f = f->next; +- } ++ q921_send_queued_iframes(pri); + } + if (pri->debug & PRI_DEBUG_Q921_DUMP) + pri_message(pri, "-- Waiting for acknowledge, restarting T200 counter\n"); +@@ -515,7 +521,7 @@ + pri->txqueue = f; + /* Immediately transmit unless we're in a recovery state, or the window + size is too big */ +- if (!pri->retrans && !pri->busy) { ++ if ((pri->q921_state == Q921_LINK_CONNECTION_ESTABLISHED) && (!pri->retrans && !pri->busy)) { + if (pri->windowlen < pri->window) { + pri->windowlen++; + q921_transmit(pri, (q921_h *)(&f->h), f->len); +@@ -532,9 +538,14 @@ + pri_schedule_del(pri, pri->t203_timer); + pri->t203_timer = 0; + } +- if (pri->debug & PRI_DEBUG_Q921_DUMP) +- pri_message(pri, "Starting T_200 timer\n"); +- reschedule_t200(pri); ++ ++ /* Check this so that we don't try to send frames while multi frame mode is down */ ++ if (pri->q921_state == Q921_LINK_CONNECTION_ESTABLISHED) { ++ if (pri->debug & PRI_DEBUG_Q921_DUMP) ++ pri_message(pri, "Starting T_200 timer\n"); ++ ++ reschedule_t200(pri); ++ } + } else { + pri_error(pri, "!! Out of memory for Q.921 transmit\n"); + return -1; +@@ -776,9 +787,6 @@ + + static pri_event *q921_dchannel_up(struct pri *pri) + { +- /* Reset counters, etc */ +- q921_reset(pri); +- + /* Stop any SABME retransmissions */ + if (pri->sabme_timer) { + pri_schedule_del(pri, pri->sabme_timer); +@@ -799,6 +807,8 @@ + /* Notify Layer 3 */ + q931_dl_indication(pri, PRI_EVENT_DCHAN_UP); + ++ q921_send_queued_iframes(pri); ++ + /* Report event that D-Channel is now up */ + pri->ev.gen.e = PRI_EVENT_DCHAN_UP; + return &pri->ev; +Index: q931.c +=================================================================== +--- a/q931.c (.../tags/1.4.9) (revision 700) ++++ b/q931.c (.../team/group/issue14292) (revision 700) +@@ -362,6 +362,11 @@ + /* We are ready to transmit single IE only */ + if (order > 1) + return 0; ++ ++ if (call->nochannelsignalling) { ++ ie->data[pos++] = 0xac; ++ return pos + 2; ++ } + + if (call->justsignalling) { + ie->data[pos++] = 0xac; /* Read the standards docs to figure this out +@@ -804,7 +809,13 @@ + ie->data[1] = 0x90; + return 4; + } +- ++ ++ if (call->nochannelsignalling) { ++ ie->data[0] = 0xa8; ++ ie->data[1] = 0x80; ++ return 4; ++ } ++ + if (call->justsignalling) { + ie->data[0] = 0xa8; + ie->data[1] = 0x80; +@@ -992,12 +1003,45 @@ + prefix, ie->data[2] >> 7, redirection_reason2str(ie->data[2] & 0x7f), ie->data[2] & 0x7f); + break; + } +- } +- while(!(ie->data[i++]& 0x80)); ++ } while(!(ie->data[i++]& 0x80)); + q931_get_number(cnum, sizeof(cnum), ie->data + i, ie->len - i); + pri_message(pri, " '%s' ]\n", cnum); + } + ++static FUNC_RECV(receive_connected_number) ++{ ++ int i = 0; ++ ++ /* To follow Q.931 (4.5.1), we must search for start of octet 4 by ++ walking through all bytes until one with ext bit (8) set to 1 */ ++ do { ++ switch(i) { ++ case 0: ++ call->connectedplan = ie->data[i] & 0x7f; ++ break; ++ case 1: ++ call->connectedpres = ie->data[i] & 0x7f; ++ break; ++ } ++ } while(!(ie->data[i++] & 0x80)); ++ q931_get_number((unsigned char *) call->connectednum, sizeof(call->connectednum), ie->data + i, ie->len - i); ++ ++ return 0; ++} ++ ++static FUNC_SEND(transmit_connected_number) ++{ ++ int datalen = strlen(call->connectednum); ++ if (datalen > 0) { ++ ie->data[0] = call->connectedplan; ++ ie->data[1] = 0x80 | call->connectedpres; ++ memcpy(ie->data + 2, call->connectednum, strlen(call->connectednum)); ++ return datalen + 4; ++ } ++ ++ return 0; ++} ++ + static FUNC_DUMP(dump_connected_number) + { + unsigned char cnum[256]; +@@ -1015,8 +1059,7 @@ + prefix, ie->data[1] >> 7, pri_pres2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f); + break; + } +- } +- while(!(ie->data[i++]& 0x80)); ++ } while(!(ie->data[i++]& 0x80)); + q931_get_number(cnum, sizeof(cnum), ie->data + i, ie->len - i); + pri_message(pri, " '%s' ]\n", cnum); + } +@@ -1040,8 +1083,7 @@ + call->redirectingreason = ie->data[i] & 0x0f; + break; + } +- } +- while(!(ie->data[i++] & 0x80)); ++ } while(!(ie->data[i++] & 0x80)); + q931_get_number((unsigned char *) call->redirectingnum, sizeof(call->redirectingnum), ie->data + i, ie->len - i); + return 0; + } +@@ -2183,7 +2225,7 @@ + { 1, Q931_IE_CALL_STATUS, "Call Status" }, + { 1, Q931_IE_CHANGE_STATUS, "Change Status" }, + { 1, Q931_IE_CONNECTED_ADDR, "Connected Number", dump_connected_number }, +- { 1, Q931_IE_CONNECTED_NUM, "Connected Number", dump_connected_number }, ++ { 1, Q931_IE_CONNECTED_NUM, "Connected Number", dump_connected_number, receive_connected_number, transmit_connected_number }, + { 1, Q931_IE_ORIGINAL_CALLED_NUMBER, "Original Called Number", dump_redirecting_number, receive_redirecting_number, transmit_redirecting_number }, + { 1, Q931_IE_USER_USER_FACILITY, "User-User Facility" }, + { 1, Q931_IE_UPDATE, "Update" }, +@@ -2478,8 +2520,7 @@ + maxlen -= res; + iet = (q931_ie *)((char *)iet + res); + } +- } +- while (res > 0 && order < ies_count); ++ } while (res > 0 && order < ies_count); + if (have_shift && total_res) { + if (Q931_IE_CODESET(ies[x].ie)) + *codeset = Q931_IE_CODESET(ies[x].ie); +@@ -2820,9 +2861,9 @@ + return send_message(pri, c, Q931_CALL_PROCEEDING, call_proceeding_ies); + } + #ifndef ALERTING_NO_PROGRESS +-static int alerting_ies[] = { Q931_PROGRESS_INDICATOR, Q931_IE_USER_USER, -1 }; ++static int alerting_ies[] = { Q931_PROGRESS_INDICATOR, Q931_IE_USER_USER, Q931_IE_FACILITY, -1 }; + #else +-static int alerting_ies[] = { -1 }; ++static int alerting_ies[] = { Q931_IE_FACILITY, -1 }; + #endif + + int q931_alerting(struct pri *pri, q931_call *c, int channel, int info) +@@ -2841,7 +2882,7 @@ + return send_message(pri, c, Q931_ALERTING, alerting_ies); + } + +-static int connect_ies[] = { Q931_CHANNEL_IDENT, Q931_PROGRESS_INDICATOR, -1 }; ++static int connect_ies[] = { Q931_CHANNEL_IDENT, Q931_PROGRESS_INDICATOR, Q931_IE_CONNECTED_NUM, Q931_IE_FACILITY, -1 }; + + int q931_setup_ack(struct pri *pri, q931_call *c, int channel, int nonisdn) + { +@@ -2923,6 +2964,18 @@ + q931_release(pri, c, PRI_CAUSE_NORMAL_CLEARING); + } + ++static void pri_cctimer2_timeout(void *data) ++{ ++ int cause = 16; ++ struct q931_call *c = data; ++ struct pri *pri = c->pri; ++ if (pri->debug & PRI_DEBUG_Q931_STATE) ++ pri_message(pri, "Timed out no-channel call\n"); ++ c->ccoperation = QSIG_CC_CANCEL; ++ /* normal clear cause */ ++ q931_hangup(pri, c, cause); ++} ++ + int q931_connect(struct pri *pri, q931_call *c, int channel, int nonisdn) + { + if (channel) { +@@ -2954,7 +3007,7 @@ + return send_message(pri, c, Q931_CONNECT, connect_ies); + } + +-static int release_ies[] = { Q931_CAUSE, Q931_IE_USER_USER, -1 }; ++static int release_ies[] = { Q931_CAUSE, Q931_IE_USER_USER, Q931_IE_FACILITY, -1 }; + + int q931_release(struct pri *pri, q931_call *c, int cause) + { +@@ -3002,7 +3055,7 @@ + return send_message(pri, c, Q931_RESTART, restart_ies); + } + +-static int disconnect_ies[] = { Q931_CAUSE, Q931_IE_USER_USER, -1 }; ++static int disconnect_ies[] = { Q931_CAUSE, Q931_IE_USER_USER, Q931_IE_FACILITY, -1 }; + + int q931_disconnect(struct pri *pri, q931_call *c, int cause) + { +@@ -3030,6 +3083,8 @@ + + static int cis_setup_ies[] = { Q931_BEARER_CAPABILITY, Q931_CHANNEL_IDENT, Q931_IE_FACILITY, Q931_CALLED_PARTY_NUMBER, -1 }; + ++static int nochannel_setup_ies[] = { Q931_BEARER_CAPABILITY, Q931_CHANNEL_IDENT, Q931_IE_FACILITY, Q931_CALLING_PARTY_NUMBER, Q931_CALLED_PARTY_NUMBER, Q931_SENDING_COMPLETE, -1 }; ++ + int q931_setup(struct pri *pri, q931_call *c, struct pri_sr *req) + { + int res; +@@ -3055,6 +3110,7 @@ + c->nonisdn = req->nonisdn; + c->newcall = 0; + c->justsignalling = req->justsignalling; ++ c->nochannelsignalling = req->nochannelsignalling; + c->complete = req->numcomplete; + if (req->exclusive) + c->chanflags = FLAG_EXCLUSIVE; +@@ -3082,6 +3138,10 @@ + } + if (req->redirectingnum) { + libpri_copy_string(c->redirectingnum, req->redirectingnum, sizeof(c->redirectingnum)); ++ if (req->redirectingname) ++ libpri_copy_string(c->redirectingname, req->redirectingname, sizeof(c->redirectingname)); ++ else ++ c->redirectingname[0] = '\0'; + c->redirectingplan = req->redirectingplan; + if ((pri->switchtype == PRI_SWITCH_DMS100) || + (pri->switchtype == PRI_SWITCH_ATT4ESS)) { +@@ -3092,6 +3152,7 @@ + c->redirectingpres = req->redirectingpres; + c->redirectingreason = req->redirectingreason; + } else { ++ c->redirectingname[0] = '\0'; + c->redirectingnum[0] = '\0'; + c->redirectingplan = PRI_UNKNOWN; + c->redirectingpres = PRES_NUMBER_NOT_AVAILABLE; +@@ -3113,12 +3174,19 @@ + else + c->progressmask = 0; + ++ if (req->ccringout) ++ c->ccoperation = QSIG_CC_RINGOUT; ++ if (req->ccbsnr) ++ c->ccoperation = req->ccbsnr; ++ + pri_call_add_standard_apdus(pri, c); + + if (pri->subchannel && !pri->bri) + res = send_message(pri, c, Q931_SETUP, gr303_setup_ies); + else if (c->justsignalling) + res = send_message(pri, c, Q931_SETUP, cis_setup_ies); ++ else if (c->nochannelsignalling) ++ res = send_message(pri, c, Q931_SETUP, nochannel_setup_ies); + else + res = send_message(pri, c, Q931_SETUP, setup_ies); + if (!res) { +@@ -3132,7 +3200,7 @@ + + } + +-static int release_complete_ies[] = { Q931_IE_USER_USER, -1 }; ++static int release_complete_ies[] = { Q931_IE_USER_USER, Q931_IE_FACILITY, -1 }; + + static int q931_release_complete(struct pri *pri, q931_call *c, int cause) + { +@@ -3187,6 +3255,18 @@ + /* We'll send RELEASE with these causes */ + disconnect = 0; + } ++ if (c->nochannelsignalling) { ++ if (c->ccoperation == QSIG_CC_CANCEL) { ++ add_qsigCcInv_facility_ie(pri, c, Q931_RELEASE); ++ } ++ if (c->cctimer2) { ++ pri_schedule_del(pri, c->cctimer2); ++ c->cctimer2 = 0; ++ pri_message(pri, "NEW_HANGUP DEBUG: stop CC-Timer2\n"); ++ } ++ disconnect = 0; ++ } ++ + /* All other causes we send with DISCONNECT */ + switch(c->ourcallstate) { + case Q931_CALL_STATE_NULL: +@@ -3227,6 +3307,10 @@ + break; + case Q931_CALL_STATE_ACTIVE: + /* received CONNECT */ ++ if (c->nochannelsignalling) { ++ q931_release(pri,c,cause); ++ break; ++ } + q931_disconnect(pri,c,cause); + break; + case Q931_CALL_STATE_DISCONNECT_REQUEST: +@@ -3260,6 +3344,132 @@ + return 0; + } + ++static void clr_subcommands(struct subcommands *sub) ++{ ++ sub->counter_subcmd = 0; ++} ++ ++static struct subcommand *get_ptr_subcommand(struct subcommands *sub) ++{ ++ if (sub->counter_subcmd < MAX_SUBCOMMANDS) { ++ int count = sub->counter_subcmd; ++ sub->counter_subcmd++; ++ return &sub->subcmd[count]; ++ } ++ ++ return NULL; ++} ++ ++static struct subcommand *get_ptr_q931_subcommand_by_index(struct subcommands *sub, int index) ++{ ++ if (index < MAX_SUBCOMMANDS) { ++ sub->counter_subcmd--; ++ return &sub->subcmd[index]; ++ } ++ ++ return NULL; ++} ++ ++static int q931_facilities2eventfacilities(struct pri *pri, q931_call *c, struct subcommands *subcmds) ++{ ++ int facilitypos; ++ int facility_number; ++ struct subcommand *c_subcmd; ++ struct subcommand *e_subcmd; ++ ++ if (c->subcmds.counter_subcmd) { ++ facility_number = c->subcmds.counter_subcmd; ++ ++ for (facilitypos = 0; facilitypos < facility_number; facilitypos++) { ++ c->subcmds.counter_subcmd--; ++ c_subcmd = get_ptr_q931_subcommand_by_index(&c->subcmds, facilitypos); ++ e_subcmd = get_ptr_subcommand(subcmds); ++ if (c_subcmd && e_subcmd) { ++ switch (c_subcmd->cmd) { ++ case CMD_CC_CCBSREQUEST_RR: ++ e_subcmd->cmd = c_subcmd->cmd; ++ memcpy(&c_subcmd->cc_ccbs_rr, &e_subcmd->cc_ccbs_rr, sizeof(c_subcmd->cc_ccbs_rr)); ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "facility(QSIG_CC_CCBSREQUEST) (%d/%d)\n", ++ e_subcmd->cc_ccbs_rr.cc_request_res.no_path_reservation, ++ e_subcmd->cc_ccbs_rr.cc_request_res.retain_service); ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "counter_subcmd(%d)\n", subcmds->counter_subcmd); ++ c->ccrequestresult = 1; ++ break; ++ case CMD_CC_CCNRREQUEST_RR: ++ e_subcmd->cmd = c_subcmd->cmd; ++ memcpy(&c_subcmd->cc_ccnr_rr, &e_subcmd->cc_ccnr_rr, sizeof(c_subcmd->cc_ccnr_rr)); ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "facility(QSIG_CC_CCNRREQUEST) (%d/%d)\n", ++ e_subcmd->cc_ccnr_rr.cc_request_res.no_path_reservation, ++ e_subcmd->cc_ccnr_rr.cc_request_res.retain_service); ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "counter_subcmd(%d)\n", subcmds->counter_subcmd); ++ c->ccrequestresult = 1; ++ break; ++ case CMD_CC_CANCEL_INV: ++ e_subcmd->cmd = c_subcmd->cmd; ++ memcpy(&c_subcmd->cc_cancel_inv, &e_subcmd->cc_cancel_inv, sizeof(c_subcmd->cc_cancel_inv)); ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "facility(QSIG_CC_CANCEL) (%s/%s)\n", ++ e_subcmd->cc_cancel_inv.cc_optional_arg.number_A, ++ e_subcmd->cc_cancel_inv.cc_optional_arg.number_B); ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "counter_subcmd(%d)\n", subcmds->counter_subcmd); ++ break; ++ case CMD_CC_EXECPOSIBLE_INV: ++ e_subcmd->cmd = c_subcmd->cmd; ++ memcpy(&c_subcmd->cc_execposible_inv, &e_subcmd->cc_execposible_inv, sizeof(c_subcmd->cc_execposible_inv)); ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "facility(QSIG_CC_EXECPOSIBLE) (%s/%s)\n", ++ e_subcmd->cc_execposible_inv.cc_optional_arg.number_A, ++ e_subcmd->cc_execposible_inv.cc_optional_arg.number_B); ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "counter_subcmd(%d)\n", subcmds->counter_subcmd); ++ break; ++ case CMD_CC_RINGOUT_INV: ++ e_subcmd->cmd = c_subcmd->cmd; ++ memcpy(&c_subcmd->cc_ringout_inv, &e_subcmd->cc_ringout_inv, sizeof(c_subcmd->cc_ringout_inv)); ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "facility(QSIG_CC_RINGOUT) (%d)\n", ++ e_subcmd->cc_ringout_inv.cc_extension.cc_extension_tag); ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "counter_subcmd(%d)\n", subcmds->counter_subcmd); ++ break; ++ case CMD_CC_SUSPEND_INV: ++ e_subcmd->cmd = c_subcmd->cmd; ++ memcpy(&c_subcmd->cc_suspend_inv, &e_subcmd->cc_suspend_inv, sizeof(c_subcmd->cc_suspend_inv)); ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "facility(QSIG_CC_SUSPEND) (%d)\n", ++ e_subcmd->cc_suspend_inv.cc_extension.cc_extension_tag); ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "counter_subcmd(%d)\n", subcmds->counter_subcmd); ++ break; ++ case CMD_CC_ERROR: ++ e_subcmd->cmd = c_subcmd->cmd; ++ memcpy(&c_subcmd->cc_error, &e_subcmd->cc_error, sizeof(c_subcmd->cc_error)); ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "facility(QSIG_CC_ERROR) (%d)\n", ++ e_subcmd->cc_error.error_value); ++ if (pri->debug & PRI_DEBUG_APDU) ++ pri_message(pri, "counter_subcmd(%d)\n", subcmds->counter_subcmd); ++ break; ++ default: ++ pri_error(pri, "Don't know how to handle Facility subcmd %d\n", c_subcmd->cmd); ++ break; ++ } ++ } ++ } ++#if 0 ++ } else { ++ pri_message(pri, "No facilities specified\n"); ++#endif ++ } ++ return 0; ++} ++ ++ + int q931_receive(struct pri *pri, q931_h *h, int len) + { + q931_mh *mh; +@@ -3312,6 +3522,7 @@ + break; + case Q931_FACILITY: + c->callername[0] = '\0'; ++ c->subcmds.counter_subcmd = 0; + break; + case Q931_SETUP: + if (pri->debug & PRI_DEBUG_Q931_STATE) +@@ -3339,6 +3550,7 @@ + c->redirectingplan = -1; + c->redirectingpres = -1; + c->redirectingreason = -1; ++ c->redirectingcount = 0; + c->origcalledplan = -1; + c->origcalledpres = -1; + c->origredirectingreason = -1; +@@ -3346,6 +3558,29 @@ + c->origcallednum[0] = '\0'; + c->redirectingname[0] = '\0'; + c->origcalledname[0] = '\0'; ++ c->connectedplan = -1; ++ c->connectedpres = -1; ++ c->connectednum[0] = '\0'; ++ c->connectedname[0] = '\0'; ++ c->divleginfo1activeflag = 0; ++ c->divertedtocount = 0; ++ c->divertedtoplan = -1; ++ c->divertedtopres = -1; ++ c->divertedtoreason = -1; ++ c->divertedtonum[0] = '\0'; ++ c->divleginfo3activeflag = 0; ++ c->divertedtoname[0] = '\0'; ++ c->divertedstate = DIVERTEDSTATE_NONE; ++ c->ctcompleteflag = 0; ++ c->ctcompleteplan = -1; ++ c->ctcompletepres = -1; ++ c->ctcompletenum[0] = '\0'; ++ c->ctcompletename[0] = '\0'; ++ c->ctactiveflag = 0; ++ c->ctactiveplan = -1; ++ c->ctactivepres = -1; ++ c->ctactivenum[0] = '\0'; ++ c->ctactivename[0] = '\0'; + c->useruserprotocoldisc = -1; + c->useruserinfo[0] = '\0'; + c->complete = 0; +@@ -3353,7 +3588,9 @@ + c->aoc_units = -1; + /* Fall through */ + case Q931_CONNECT: ++ c->ccrequestresult = 0; + case Q931_ALERTING: ++ c->subcmds.counter_subcmd = 0; + case Q931_PROGRESS: + c->useruserinfo[0] = '\0'; + c->cause = -1; +@@ -3369,6 +3606,7 @@ + break; + case Q931_RELEASE: + case Q931_DISCONNECT: ++ c->subcmds.counter_subcmd = 0; + c->cause = -1; + c->causecode = -1; + c->causeloc = -1; +@@ -3383,6 +3621,7 @@ + pri_schedule_del(pri, c->retranstimer); + c->retranstimer = 0; + c->useruserinfo[0] = '\0'; ++ c->subcmds.counter_subcmd = 0; + /* Fall through */ + case Q931_STATUS: + c->cause = -1; +@@ -3539,6 +3778,9 @@ + if (!c->newcall) { + break; + } ++ ++ clr_subcommands(&pri->ev.ring.subcmds); ++ + if (c->progressmask & PRI_PROG_CALLER_NOT_ISDN) + c->nonisdn = 1; + c->newcall = 0; +@@ -3570,7 +3812,9 @@ + libpri_copy_string(pri->ev.ring.redirectingname, c->redirectingname, sizeof(pri->ev.ring.redirectingname)); + libpri_copy_string(pri->ev.ring.useruserinfo, c->useruserinfo, sizeof(pri->ev.ring.useruserinfo)); + c->useruserinfo[0] = '\0'; ++ pri->ev.ring.redirectingpres = c->redirectingpres; + pri->ev.ring.redirectingreason = c->redirectingreason; ++ pri->ev.ring.redirectingcount = c->redirectingcount; + pri->ev.ring.origredirectingreason = c->origredirectingreason; + pri->ev.ring.flexible = ! (c->chanflags & FLAG_EXCLUSIVE); + pri->ev.ring.cref = c->cr; +@@ -3578,15 +3822,21 @@ + pri->ev.ring.layer1 = c->userl1; + pri->ev.ring.complete = c->complete; + pri->ev.ring.ctype = c->transcapability; +- pri->ev.ring.redirectingreason = c->redirectingreason; + pri->ev.ring.progress = c->progress; + pri->ev.ring.progressmask = c->progressmask; ++ if (pri->debug & PRI_DEBUG_APDU) { ++ pri_message(pri, "Sending ring event (%d) nochannelsignalling (%d) facility_number (%d)\n", ++ pri->ev.ring.cref, c->nochannelsignalling, pri->ev.ring.subcmds.counter_subcmd); ++ } ++ q931_facilities2eventfacilities(pri, c, &pri->ev.ring.subcmds); + return Q931_RES_HAVEEVENT; + case Q931_ALERTING: + if (c->newcall) { + q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); + break; + } ++ clr_subcommands(&pri->ev.ringing.subcmds); ++ + UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_CALL_DELIVERED); + c->peercallstate = Q931_CALL_STATE_CALL_RECEIVED; + pri->ev.e = PRI_EVENT_RINGING; +@@ -3595,8 +3845,26 @@ + pri->ev.ringing.call = c; + pri->ev.ringing.progress = c->progress; + pri->ev.ringing.progressmask = c->progressmask; ++ ++ if (c->divleginfo3activeflag) { ++ c->divleginfo3activeflag = 0; ++ libpri_copy_string(pri->ev.ringing.calledname, c->divertedtoname, sizeof(pri->ev.ringing.calledname)); ++ libpri_copy_string(pri->ev.ringing.callednum, (c->divertedtonum[0]) ? c->divertedtonum : c->callednum, sizeof(pri->ev.ringing.callednum)); ++ pri->ev.ringing.calledpres = c->divertedtopres; ++ pri->ev.ringing.calledplan = c->divertedtoplan; ++ } else { ++ libpri_copy_string(pri->ev.ringing.calledname, c->calledname, sizeof(pri->ev.ringing.calledname)); ++ libpri_copy_string(pri->ev.ringing.callednum, (c->divertedtonum[0]) ? c->divertedtonum : c->callednum, sizeof(pri->ev.ringing.callednum)); ++ pri->ev.ringing.calledpres = PRES_ALLOWED_USER_NUMBER_NOT_SCREENED; ++ pri->ev.ringing.calledplan = c->calledplan; ++ } + libpri_copy_string(pri->ev.ringing.useruserinfo, c->useruserinfo, sizeof(pri->ev.ringing.useruserinfo)); + c->useruserinfo[0] = '\0'; ++ if (pri->debug & PRI_DEBUG_APDU) { ++ pri_message(pri, "Sending ringing event (%d) nochannelsignalling (%d) facility_number (%d)\n", ++ pri->ev.ringing.cref, c->nochannelsignalling, pri->ev.ringing.subcmds.counter_subcmd); ++ } ++ q931_facilities2eventfacilities(pri, c, &pri->ev.ringing.subcmds); + + cur = c->apdus; + while (cur) { +@@ -3617,6 +3885,8 @@ + q931_status(pri, c, PRI_CAUSE_WRONG_MESSAGE); + break; + } ++ clr_subcommands(&pri->ev.answer.subcmds); ++ + UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_ACTIVE); + c->peercallstate = Q931_CALL_STATE_CONNECT_REQUEST; + pri->ev.e = PRI_EVENT_ANSWER; +@@ -3625,31 +3895,166 @@ + pri->ev.answer.call = c; + pri->ev.answer.progress = c->progress; + pri->ev.answer.progressmask = c->progressmask; ++ libpri_copy_string(pri->ev.answer.connectednum, c->connectednum, sizeof(pri->ev.answer.connectednum)); ++ libpri_copy_string(pri->ev.answer.connectedname, c->connectedname, sizeof(pri->ev.answer.connectedname)); ++ pri->ev.answer.connectedpres = c->connectedpres; ++ pri->ev.answer.connectedplan = c->connectedplan; ++ pri->ev.answer.source = PRI_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; + libpri_copy_string(pri->ev.answer.useruserinfo, c->useruserinfo, sizeof(pri->ev.answer.useruserinfo)); + c->useruserinfo[0] = '\0'; ++ if (pri->debug & PRI_DEBUG_APDU) { ++ pri_message(pri, "Sending answer event (%d) nochannelsignalling (%d) facility_number (%d)\n", ++ pri->ev.answer.cref, c->nochannelsignalling, pri->ev.answer.subcmds.counter_subcmd); ++ } ++ q931_facilities2eventfacilities(pri, c, &pri->ev.answer.subcmds); + q931_connect_acknowledge(pri, c); ++ if (c->nochannelsignalling) { ++ if (c->ccrequestresult) { ++ pri_message(pri, "Q931_CONNECT: start CC-Timer2\n"); ++ c->cctimer2 = pri_schedule_event(pri, pri->timers[PRI_TIMER_CCBST2], pri_cctimer2_timeout, c); ++ } ++ return Q931_RES_HAVEEVENT; ++ } + if (c->justsignalling) { /* Make sure WE release when we initiatie a signalling only connection */ + q931_release(pri, c, PRI_CAUSE_NORMAL_CLEARING); + break; + } else + return Q931_RES_HAVEEVENT; + case Q931_FACILITY: +- if (c->newcall) { +- q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); +- break; ++ { ++ int haveevent = 0; ++ clr_subcommands(&pri->ev.facility.subcmds); ++ ++ if (c->newcall) { ++ q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); ++ break; ++ } ++ if (c->subcmds.counter_subcmd) { ++ pri->ev.e = PRI_EVENT_FACILITY; ++ pri->ev.facility.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); ++ pri->ev.facility.cref = c->cr; ++ pri->ev.facility.call = c; ++ ++ if (pri->debug & PRI_DEBUG_APDU) { ++ pri_message(pri, "Sending facility event (%d) nochannelsignalling (%d) facility_number (%d)\n", ++ pri->ev.facility.cref, c->nochannelsignalling, pri->ev.facility.subcmds.counter_subcmd); ++ } ++ q931_facilities2eventfacilities(pri, c, &pri->ev.facility.subcmds); ++ haveevent = 1; ++ } ++ if (c->ctcompleteflag) { ++ c->ctcompleteflag = 0; ++ ++ if (c->ctcompletecallstatus == 0) { ++ /* answered(0) */ ++ struct subcommand *subcmd; ++ ++ pri_message(pri, "Got CT-Complete, callStatus = answered(0)\n"); ++ pri->ev.e = PRI_EVENT_FACILITY; ++ pri->ev.facility.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); ++ pri->ev.facility.call = c; ++ ++ subcmd = get_ptr_subcommand(&pri->ev.facility.subcmds); ++ if (subcmd) { ++ struct cmd_connectedline *cmdcl = &subcmd->connectedline; ++ ++ subcmd->cmd = CMD_CONNECTEDLINE; ++ libpri_copy_string(cmdcl->connected.id.number, c->ctcompletenum, sizeof(cmdcl->connected.id.number)); ++ libpri_copy_string(cmdcl->connected.id.name, c->ctcompletename, sizeof(cmdcl->connected.id.name)); ++ cmdcl->connected.id.number_type = c->ctcompleteplan; ++ cmdcl->connected.id.number_presentation = c->ctcompletepres; ++ cmdcl->connected.source = PRI_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; ++ haveevent = 1; ++ pri_message(pri, "CT-Complete, sending facility/CMD_CONNECTEDLINE (%s/%s)\n", cmdcl->connected.id.name, cmdcl->connected.id.number); ++ } ++ } else if (c->ctcompletecallstatus == 1) { ++ /* alerting(1) */ ++ struct subcommand *subcmd; ++ ++ pri_message(pri, "Got CT-Complete, callStatus = alerting(1)\n"); ++ pri->ev.e = PRI_EVENT_FACILITY; ++ pri->ev.facility.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); ++ pri->ev.facility.call = c; ++ ++ subcmd = get_ptr_subcommand(&pri->ev.facility.subcmds); ++ if (subcmd) { ++ struct cmd_redirecting *cmdr = &subcmd->redirecting; ++ ++ subcmd->cmd = CMD_REDIRECTING; ++ libpri_copy_string(cmdr->redirecting.from.number, c->connectednum, sizeof(cmdr->redirecting.from.number)); ++ libpri_copy_string(cmdr->redirecting.from.name, c->connectedname, sizeof(cmdr->redirecting.from.name)); ++ cmdr->redirecting.from.number_type = c->connectedplan; ++ cmdr->redirecting.from.number_presentation = c->connectedpres; ++ libpri_copy_string(cmdr->redirecting.to.number, c->ctcompletenum, sizeof(cmdr->redirecting.to.number)); ++ libpri_copy_string(cmdr->redirecting.to.name, c->ctcompletename, sizeof(cmdr->redirecting.to.name)); ++ cmdr->redirecting.to.number_type = c->ctcompleteplan; ++ cmdr->redirecting.to.number_presentation = c->ctcompletepres; ++ cmdr->redirecting.count = 0; ++ cmdr->redirecting.reason = PRI_REDIR_UNKNOWN; ++ haveevent = 1; ++ pri_message(pri, "CT-Complete, sending facility/CMD_REDIRECTING (%s/%s)\n", cmdr->redirecting.to.name, cmdr->redirecting.to.number); ++ } ++ } else { ++ pri_message(pri, "illegal value for callStatus=%d\n", c->ctcompletecallstatus); ++ } ++ } else if (c->ctactiveflag) { ++ struct subcommand *subcmd; ++ ++ c->ctactiveflag = 0; ++ ++ pri_message(pri, "Got CT-Active\n"); ++ pri->ev.e = PRI_EVENT_FACILITY; ++ pri->ev.facility.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); ++ pri->ev.facility.call = c; ++ ++ subcmd = get_ptr_subcommand(&pri->ev.facility.subcmds); ++ if (subcmd) { ++ struct cmd_connectedline *cmdcl = &subcmd->connectedline; ++ ++ subcmd->cmd = CMD_CONNECTEDLINE; ++ libpri_copy_string(cmdcl->connected.id.number, c->ctcompletenum, sizeof(cmdcl->connected.id.number)); ++ libpri_copy_string(cmdcl->connected.id.name, c->ctcompletename, sizeof(cmdcl->connected.id.name)); ++ cmdcl->connected.id.number_type = c->ctcompleteplan; ++ cmdcl->connected.id.number_presentation = c->ctcompletepres; ++ cmdcl->connected.source = PRI_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; ++ haveevent = 1; ++ pri_message(pri, "CT-Active, sending facility CMD_CONNECTEDLINE (%s/%s)\n", cmdcl->connected.id.name, cmdcl->connected.id.number); ++ } ++ } ++ else if (c->divleginfo1activeflag) { ++ struct subcommand *subcmd; ++ ++ c->divleginfo1activeflag = 0; ++ ++ pri_message(pri, "Got DivertingLegInformation1\n"); ++ pri->ev.e = PRI_EVENT_FACILITY; ++ pri->ev.facility.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); ++ pri->ev.facility.call = c; ++ ++ subcmd = get_ptr_subcommand(&pri->ev.facility.subcmds); ++ if (subcmd) { ++ struct cmd_redirecting *cmdr = &subcmd->redirecting; ++ ++ subcmd->cmd = CMD_REDIRECTING; ++ libpri_copy_string(cmdr->redirecting.from.number, c->callednum, sizeof(cmdr->redirecting.from.number)); ++ cmdr->redirecting.from.name[0] = '\0'; ++ cmdr->redirecting.from.number_type = c->calledplan; ++ cmdr->redirecting.from.number_presentation = PRES_ALLOWED_USER_NUMBER_NOT_SCREENED; ++ libpri_copy_string(cmdr->redirecting.to.number, c->divertedtonum, sizeof(cmdr->redirecting.to.number)); ++ cmdr->redirecting.to.name[0] = '\0'; ++ cmdr->redirecting.to.number_type = c->divertedtoplan; ++ cmdr->redirecting.to.number_presentation = c->divertedtopres; ++ cmdr->redirecting.count = c->divertedtocount; ++ cmdr->redirecting.reason = c->divertedtoreason; ++ haveevent = 1; ++ pri_message(pri, "DivertingLegInformation1, sending facility/CMD_REDIRECTING (%s/%s)\n", cmdr->redirecting.to.name, cmdr->redirecting.to.number); ++ } ++ } ++ ++ if (haveevent) ++ return Q931_RES_HAVEEVENT; + } +- pri->ev.e = PRI_EVENT_FACNAME; +- libpri_copy_string(pri->ev.facname.callingname, c->callername, sizeof(pri->ev.facname.callingname)); +- libpri_copy_string(pri->ev.facname.callingnum, c->callernum, sizeof(pri->ev.facname.callingnum)); +- pri->ev.facname.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); +- pri->ev.facname.callingpres = c->callerpres; +- pri->ev.facname.callingplan = c->callerplan; +- pri->ev.facname.cref = c->cr; +- pri->ev.facname.call = c; +-#if 0 +- pri_message(pri, "Sending facility event (%s/%s)\n", pri->ev.facname.callingname, pri->ev.facname.callingnum); +-#endif +- return Q931_RES_HAVEEVENT; ++ break; + case Q931_PROGRESS: + if (missingmand) { + q931_status(pri, c, PRI_CAUSE_MANDATORY_IE_MISSING); +@@ -3757,6 +4162,8 @@ + } + break; + case Q931_RELEASE_COMPLETE: ++ clr_subcommands(&pri->ev.hangup.subcmds); ++ + UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL); + c->peercallstate = Q931_CALL_STATE_NULL; + pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); +@@ -3766,6 +4173,11 @@ + pri->ev.hangup.aoc_units = c->aoc_units; + libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.hangup.useruserinfo)); + c->useruserinfo[0] = '\0'; ++ if (pri->debug & PRI_DEBUG_APDU) { ++ pri_message(pri, "Sending hangup event (%d) nochannelsignalling (%d) facility_number (%d)\n", ++ pri->ev.hangup.cref, c->nochannelsignalling, pri->ev.hangup.subcmds.counter_subcmd); ++ } ++ q931_facilities2eventfacilities(pri, c, &pri->ev.hangup.subcmds); + /* Free resources */ + if (c->alive) { + pri->ev.e = PRI_EVENT_HANGUP; +@@ -3783,6 +4195,8 @@ + q931_hangup(pri,c,c->cause); + break; + case Q931_RELEASE: ++ clr_subcommands(&pri->ev.hangup.subcmds); ++ + if (missingmand) { + /* Force cause to be mandatory IE missing */ + c->cause = PRI_CAUSE_MANDATORY_IE_MISSING; +@@ -3801,6 +4215,11 @@ + pri->ev.hangup.aoc_units = c->aoc_units; + libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.hangup.useruserinfo)); + c->useruserinfo[0] = '\0'; ++ if (pri->debug & PRI_DEBUG_APDU) { ++ pri_message(pri, "Sending hangup event (%d) nochannelsignalling (%d) facility_number (%d)\n", ++ pri->ev.hangup.cref, c->nochannelsignalling, pri->ev.hangup.subcmds.counter_subcmd); ++ } ++ q931_facilities2eventfacilities(pri, c, &pri->ev.hangup.subcmds); + /* Don't send release complete if they send us release + while we sent it, assume a NULL state */ + if (c->newcall) +@@ -3809,6 +4228,8 @@ + return Q931_RES_HAVEEVENT; + break; + case Q931_DISCONNECT: ++ clr_subcommands(&pri->ev.hangup.subcmds); ++ + if (missingmand) { + /* Still let user call release */ + c->cause = PRI_CAUSE_MANDATORY_IE_MISSING; +@@ -3835,6 +4256,11 @@ + pri->ev.hangup.aoc_units = c->aoc_units; + libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.hangup.useruserinfo)); + c->useruserinfo[0] = '\0'; ++ if (pri->debug & PRI_DEBUG_APDU) { ++ pri_message(pri, "Sending hangup event (%d) nochannelsignalling (%d) facility_number (%d)\n", ++ pri->ev.hangup.cref, c->nochannelsignalling, pri->ev.hangup.subcmds.counter_subcmd); ++ } ++ q931_facilities2eventfacilities(pri, c, &pri->ev.hangup.subcmds); + if (c->alive) + return Q931_RES_HAVEEVENT; + else + +Property changes on: . +___________________________________________________________________ +Added: automerge + + * +Added: automerge-propname + + issue14292-integrated +Added: svnmerge-integrated + + /branches/1.4:1-688 +Added: automerge-email + + rmudgett@digium.com +Added: issue14292-integrated + + /team/group/issue14068:1-699 + |