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