Index: pri_facility.c =================================================================== --- pri_facility.c (revision 382) +++ pri_facility.c (working copy) @@ -1142,6 +1142,134 @@ } /* End EECT */ +/* AFN-PR */ +extern int anfpr_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2) +{ + /* Did all the tests to see if we're on the same PRI and + * are on a compatible switchtype */ + /* TODO */ + int i = 0; + int res = 0; + unsigned char buffer[255] = ""; + unsigned short call_reference = c2->cr; + struct rose_component *comp = NULL, *compstk[10]; + int compsp = 0; + static unsigned char op_tag[] = { + 0x0C, + }; + + /* Channel 1 */ + buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS); + /* Interpretation component */ + + ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i); + ASN1_PUSH(compstk, compsp, comp); + ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0); + ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0); + ASN1_FIXUP(compstk, compsp, buffer, i); + + ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 2); /* reject - to get feedback from QSIG switch */ + + ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i); + ASN1_PUSH(compstk, compsp, comp); + + ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri)); + + res = asn1_string_encode(ASN1_INTEGER, &buffer[i], sizeof(buffer)-i, sizeof(op_tag), op_tag, sizeof(op_tag)); + if (res < 0) + return -1; + i += res; + + ASN1_ADD_SIMPLE(comp, (ASN1_SEQUENCE | ASN1_CONSTRUCTOR), buffer, i); + ASN1_PUSH(compstk, compsp, comp); + buffer[i++] = (0x0a); + buffer[i++] = (0x01); + buffer[i++] = (0x00); + buffer[i++] = (0x81); + buffer[i++] = (0x00); + buffer[i++] = (0x0a); + buffer[i++] = (0x01); + buffer[i++] = (0x01); + ASN1_ADD_WORDCOMP(comp, ASN1_INTEGER, buffer, i, call_reference); + ASN1_FIXUP(compstk, compsp, buffer, i); + ASN1_FIXUP(compstk, compsp, buffer, i); + + res = pri_call_apdu_queue(c1, Q931_FACILITY, buffer, i, NULL, NULL); + if (res) { + pri_message(pri, "Could not queue ADPU in facility message\n"); + return -1; + } + + /* Remember that if we queue a facility IE for a facility message we + * have to explicitly send the facility message ourselves */ + + res = q931_facility(c1->pri, c1); + if (res) { + pri_message(pri, "Could not schedule facility message for call %d\n", c1->cr); + return -1; + } + + /* Channel 2 */ + i = 0; + res = 0; + unsigned char buffer2[255] = ""; + compsp = 0; + + buffer2[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS); + /* Interpretation component */ + + ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer2, i); + ASN1_PUSH(compstk, compsp, comp); + ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer2, i, 0); + ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer2, i, 0); + ASN1_FIXUP(compstk, compsp, buffer2, i); + + ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer2, i, 2); /* reject */ + + ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer2, i); + ASN1_PUSH(compstk, compsp, comp); + + ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer2, i, get_invokeid(pri)); + + res = asn1_string_encode(ASN1_INTEGER, &buffer2[i], sizeof(buffer2)-i, sizeof(op_tag), op_tag, sizeof(op_tag)); + if (res < 0) + return -1; + i += res; + + ASN1_ADD_SIMPLE(comp, (ASN1_SEQUENCE | ASN1_CONSTRUCTOR), buffer2, i); + ASN1_PUSH(compstk, compsp, comp); + buffer2[i++] = (0x0a); + buffer2[i++] = (0x01); + buffer2[i++] = (0x01); + buffer2[i++] = (0x81); + buffer2[i++] = (0x00); + buffer2[i++] = (0x0a); + buffer2[i++] = (0x01); + buffer2[i++] = (0x01); + ASN1_ADD_WORDCOMP(comp, ASN1_INTEGER, buffer2, i, call_reference); + ASN1_FIXUP(compstk, compsp, buffer2, i); + ASN1_FIXUP(compstk, compsp, buffer2, i); + + + res = pri_call_apdu_queue(c2, Q931_FACILITY, buffer2, i, NULL, NULL); + if (res) { + pri_message(pri, "Could not queue ADPU in facility message\n"); + return -1; + } + + /* Remember that if we queue a facility IE for a facility message we + * have to explicitly send the facility message ourselves */ + + res = q931_facility(c2->pri, c2); + if (res) { + pri_message(pri, "Could not schedule facility message for call %d\n", c1->cr); + return -1; + } + + return 0; +} +/* End AFN-PR */ + /* AOC */ static int aoc_aoce_charging_request_decode(struct pri *pri, q931_call *call, unsigned char *data, int len) { @@ -1545,6 +1673,7 @@ int rose_invoke_decode(struct pri *pri, q931_call *call, unsigned char *data, int len) { int i = 0; + int res = 0; int operation_tag; unsigned char *vdata = data; struct rose_component *comp = NULL, *invokeid = NULL, *operationid = NULL; @@ -1649,6 +1778,58 @@ 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; + } + + i = 0; + unsigned char buffer[255] = ""; + struct rose_component *comp = NULL, *compstk[10]; + int compsp = 0; + + /* Build Header */ + buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS); + /* Interpretation component */ + + ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i); + ASN1_PUSH(compstk, compsp, comp); + ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0); + ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0); + ASN1_FIXUP(compstk, compsp, buffer, i); + + ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 2); /* reject - to get feedback from QSIG switch */ + + /* Terrible Hack! + * Needed INVOKE PDU(A1) from above header build */ + buffer[i-3] = (0xa1); + char datalen[4]; + sprintf(datalen, "0x%x", strlen(data)+4); + buffer[i-2] = strtoul(datalen, NULL, 16); + + /* Add PURPOSE component from other channel to header to complete message */ + strcat(&buffer[i], &data[1]); + i += (len-1); + + /* Send message */ + res = pri_call_apdu_queue(call->bridged_call, Q931_FACILITY, buffer, i, NULL, NULL); + if (res) { + pri_message(pri, "Could not queue ADPU in facility message\n"); + return -1; + } + + /* Remember that if we queue a facility IE for a facility message we + * have to explicitly send the facility message ourselves */ + + res = q931_facility(call->bridged_call->pri, call->bridged_call); + if (res) { + pri_message(pri, "Could not schedule facility message for call %d\n", call->bridged_call->cr); + return -1; + } + break; default: if (pri->debug & PRI_DEBUG_APDU) { pri_message(pri, "!! Unable to handle ROSE operation %d", operation_tag); Index: pri_facility.h =================================================================== --- pri_facility.h (revision 382) +++ pri_facility.h (working copy) @@ -48,6 +48,7 @@ #define ROSE_AOC_IDENTIFICATION_OF_CHARGE 37 /* Q.SIG operations */ #define SS_CNID_CALLINGNAME 0 +#define SS_ANFPR_PATHREPLACEMENT 4 #define SS_DIVERTING_LEG_INFORMATION2 21 #define SS_MWI_ACTIVATE 80 #define SS_MWI_DEACTIVATE 81 @@ -266,6 +267,9 @@ int rlt_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2); +/* starts a QSIG Path Replacement */ +extern int anfpr_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2); + /* 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 */ Index: pri.c =================================================================== --- pri.c (revision 382) +++ pri.c (working copy) @@ -544,6 +544,12 @@ if (call1->pri->switchtype == PRI_SWITCH_DMS100) return rlt_initiate_transfer(call1->pri, call1, call2); + if (call1->pri->switchtype == PRI_SWITCH_QSIG) { + call1->bridged_call = call2; + call2->bridged_call = call1; + return anfpr_initiate_transfer(call1->pri, call1, call2); + } + return -1; } Index: pri_internal.h =================================================================== --- pri_internal.h (revision 382) +++ pri_internal.h (working copy) @@ -246,6 +246,9 @@ int transferable; unsigned int rlt_call_id; /* RLT call id */ + + /* Bridged call info */ + q931_call *bridged_call; /* Pointer to other leg of bridged call */ }; extern int pri_schedule_event(struct pri *pri, int ms, void (*function)(void *data), void *data);