Numerous updates for RLT (just remember, trunk can be a bumpy ride)
git-svn-id: https://origsvn.digium.com/svn/libpri/trunk@297 2fbb986a-6c06-0410-b554-c9c1f0a7f128
This commit is contained in:
parent
cb7b843e10
commit
0e2e37b537
9
pri.c
9
pri.c
@ -543,10 +543,13 @@ int pri_channel_bridge(q931_call *call1, q931_call *call2)
|
||||
if (call1->pri != call2->pri)
|
||||
return -1;
|
||||
|
||||
if (eect_initiate_transfer(call1->pri, call1, call2))
|
||||
return -1;
|
||||
if (call1->pri->switchtype == PRI_SWITCH_LUCENT5E)
|
||||
return eect_initiate_transfer(call1->pri, call1, call2);
|
||||
|
||||
return 0;
|
||||
if (call1->pri->switchtype == PRI_SWITCH_DMS100)
|
||||
return rlt_initiate_transfer(call1->pri, call1, call2);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int pri_hangup(struct pri *pri, q931_call *call, int cause)
|
||||
|
278
pri_facility.c
278
pri_facility.c
@ -838,6 +838,84 @@ static int rose_diverting_leg_information2_encode(struct pri *pri, q931_call *ca
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Send the rltThirdParty: Invoke */
|
||||
extern int rlt_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2)
|
||||
{
|
||||
int i = 0;
|
||||
unsigned char buffer[256];
|
||||
struct rose_component *comp = NULL, *compstk[10];
|
||||
const unsigned char rlt_3rd_pty = RLT_THIRD_PARTY;
|
||||
q931_call *callwithid = NULL, *apdubearer = NULL;
|
||||
int compsp = 0;
|
||||
|
||||
if (c2->transferable) {
|
||||
apdubearer = c1;
|
||||
callwithid = c2;
|
||||
} else if (c1->transferable) {
|
||||
apdubearer = c2;
|
||||
callwithid = c1;
|
||||
} else
|
||||
return -1;
|
||||
|
||||
buffer[i++] = (0x80 | Q932_PROTOCOL_ROSE);
|
||||
buffer[i++] = (0x80 | RLT_SERVICE_ID); /* Service Identifier octet */
|
||||
|
||||
ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
|
||||
ASN1_PUSH(compstk, compsp, comp);
|
||||
|
||||
/* Invoke ID is set to the operation ID */
|
||||
ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, rlt_3rd_pty);
|
||||
|
||||
/* Operation Tag */
|
||||
ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, rlt_3rd_pty);
|
||||
|
||||
/* Additional RLT invoke info - Octet 12 */
|
||||
ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
|
||||
ASN1_PUSH(compstk, compsp, comp);
|
||||
|
||||
ASN1_ADD_WORDCOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, callwithid->rlt_call_id & 0xFFFFFF); /* Length is 3 octets */
|
||||
/* Reason for redirect - unused, set to 129 */
|
||||
ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), buffer, i, 0);
|
||||
ASN1_FIXUP(compstk, compsp, buffer, i);
|
||||
ASN1_FIXUP(compstk, compsp, buffer, i);
|
||||
|
||||
if (pri_call_apdu_queue(apdubearer, Q931_FACILITY, buffer, i, NULL, NULL))
|
||||
return -1;
|
||||
|
||||
if (q931_facility(apdubearer->pri, apdubearer)) {
|
||||
pri_message(pri, "Could not schedule facility message for call %d\n", apdubearer->cr);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_dms100_transfer_ability_apdu(struct pri *pri, q931_call *c)
|
||||
{
|
||||
int i = 0;
|
||||
unsigned char buffer[256];
|
||||
struct rose_component *comp = NULL, *compstk[10];
|
||||
const unsigned char rlt_op_ind = RLT_OPERATION_IND;
|
||||
int compsp = 0;
|
||||
|
||||
buffer[i++] = (0x80 | Q932_PROTOCOL_ROSE);
|
||||
buffer[i++] = (0x80 | RLT_SERVICE_ID); /* Service Identifier octet */
|
||||
|
||||
ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
|
||||
ASN1_PUSH(compstk, compsp, comp);
|
||||
|
||||
/* Invoke ID is set to the operation ID */
|
||||
ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, rlt_op_ind);
|
||||
|
||||
/* Operation Tag - basically the same as the invoke ID tag */
|
||||
ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, rlt_op_ind);
|
||||
ASN1_FIXUP(compstk, compsp, buffer, i);
|
||||
|
||||
if (pri_call_apdu_queue(c, Q931_SETUP, buffer, i, NULL, NULL))
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Sending callername information functions */
|
||||
static int add_callername_facility_ies(struct pri *pri, q931_call *c, int cpe)
|
||||
{
|
||||
@ -1270,6 +1348,200 @@ static int aoc_aoce_charging_unit_encode(struct pri *pri, q931_call *c, long cha
|
||||
}
|
||||
/* End AOC */
|
||||
|
||||
extern int rose_reject_decode(struct pri *pri, q931_call *call, unsigned char *data, int len)
|
||||
{
|
||||
int i = 0;
|
||||
int problemtag = -1;
|
||||
int problem = -1;
|
||||
int invokeidvalue = -1;
|
||||
unsigned char *vdata = data;
|
||||
struct rose_component *comp = NULL;
|
||||
char *problemtagstr, *problemstr;
|
||||
|
||||
do {
|
||||
/* Invoke ID stuff */
|
||||
GET_COMPONENT(comp, i, vdata, len);
|
||||
CHECK_COMPONENT(comp, INVOKE_IDENTIFIER, "Don't know what to do if first ROSE component is of type 0x%x\n");
|
||||
ASN1_GET_INTEGER(comp, invokeidvalue);
|
||||
NEXT_COMPONENT(comp, i);
|
||||
|
||||
GET_COMPONENT(comp, i, vdata, len);
|
||||
problemtag = comp->type;
|
||||
problem = comp->data[0];
|
||||
|
||||
if (pri->switchtype == PRI_SWITCH_DMS100) {
|
||||
switch (problemtag) {
|
||||
case 0x80:
|
||||
problemtagstr = "General problem";
|
||||
break;
|
||||
case 0x81:
|
||||
problemtagstr = "Invoke problem";
|
||||
break;
|
||||
case 0x82:
|
||||
problemtagstr = "Return result problem";
|
||||
break;
|
||||
case 0x83:
|
||||
problemtagstr = "Return error problem";
|
||||
break;
|
||||
default:
|
||||
problemtagstr = "Unknown";
|
||||
}
|
||||
|
||||
switch (problem) {
|
||||
case 0x00:
|
||||
problemstr = "Unrecognized component";
|
||||
break;
|
||||
case 0x01:
|
||||
problemstr = "Mistyped component";
|
||||
break;
|
||||
case 0x02:
|
||||
problemstr = "Badly structured component";
|
||||
break;
|
||||
default:
|
||||
problemstr = "Unknown";
|
||||
}
|
||||
|
||||
pri_error(pri, "ROSE REJECT:\n");
|
||||
pri_error(pri, "\tINVOKE ID: 0x%X\n", invokeidvalue);
|
||||
pri_error(pri, "\tPROBLEM TYPE: %s (0x%x)\n", problemtagstr, problemtag);
|
||||
pri_error(pri, "\tPROBLEM: %s (0x%x)\n", problemstr, problem);
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
pri_message(pri, "Unable to handle return result on switchtype %d!\n", pri->switchtype);
|
||||
return -1;
|
||||
}
|
||||
|
||||
} while(0);
|
||||
|
||||
return -1;
|
||||
}
|
||||
extern int rose_return_error_decode(struct pri *pri, q931_call *call, unsigned char *data, int len)
|
||||
{
|
||||
int i = 0;
|
||||
int errorvalue = -1;
|
||||
int invokeidvalue = -1;
|
||||
unsigned char *vdata = data;
|
||||
struct rose_component *comp = NULL;
|
||||
char *invokeidstr, *errorstr;
|
||||
|
||||
do {
|
||||
/* Invoke ID stuff */
|
||||
GET_COMPONENT(comp, i, vdata, len);
|
||||
CHECK_COMPONENT(comp, INVOKE_IDENTIFIER, "Don't know what to do if first ROSE component is of type 0x%x\n");
|
||||
ASN1_GET_INTEGER(comp, invokeidvalue);
|
||||
NEXT_COMPONENT(comp, i);
|
||||
|
||||
GET_COMPONENT(comp, i, vdata, len);
|
||||
CHECK_COMPONENT(comp, ASN1_INTEGER, "Don't know what to do if second component in return error is 0x%x\n");
|
||||
ASN1_GET_INTEGER(comp, errorvalue);
|
||||
|
||||
if (pri->switchtype == PRI_SWITCH_DMS100) {
|
||||
switch (invokeidvalue) {
|
||||
case RLT_OPERATION_IND:
|
||||
invokeidstr = "RLT_OPERATION_IND";
|
||||
break;
|
||||
case RLT_THIRD_PARTY:
|
||||
invokeidstr = "RLT_THIRD_PARTY";
|
||||
break;
|
||||
default:
|
||||
invokeidstr = "Unknown";
|
||||
}
|
||||
|
||||
switch (errorvalue) {
|
||||
case 0x10:
|
||||
errorstr = "RLT Bridge Fail";
|
||||
break;
|
||||
case 0x11:
|
||||
errorstr = "RLT Call ID Not Found";
|
||||
break;
|
||||
case 0x12:
|
||||
errorstr = "RLT Not Allowed";
|
||||
break;
|
||||
case 0x13:
|
||||
errorstr = "RLT Switch Equip Congs";
|
||||
break;
|
||||
default:
|
||||
errorstr = "Unknown";
|
||||
}
|
||||
|
||||
pri_error(pri, "ROSE RETURN ERROR:\n");
|
||||
pri_error(pri, "\tOPERATION: %s\n", invokeidstr);
|
||||
pri_error(pri, "\tERROR: %s\n", errorstr);
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
pri_message(pri, "Unable to handle return result on switchtype %d!\n", pri->switchtype);
|
||||
return -1;
|
||||
}
|
||||
|
||||
} while(0);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern int rose_return_result_decode(struct pri *pri, q931_call *call, unsigned char *data, int len)
|
||||
{
|
||||
int i = 0;
|
||||
int operationidvalue = -1;
|
||||
int invokeidvalue = -1;
|
||||
unsigned char *vdata = data;
|
||||
struct rose_component *comp = NULL;
|
||||
|
||||
do {
|
||||
/* Invoke ID stuff */
|
||||
GET_COMPONENT(comp, i, vdata, len);
|
||||
CHECK_COMPONENT(comp, INVOKE_IDENTIFIER, "Don't know what to do if first ROSE component is of type 0x%x\n");
|
||||
ASN1_GET_INTEGER(comp, invokeidvalue);
|
||||
NEXT_COMPONENT(comp, i);
|
||||
|
||||
if (pri->switchtype == PRI_SWITCH_DMS100) {
|
||||
switch (invokeidvalue) {
|
||||
case RLT_THIRD_PARTY:
|
||||
if (pri->debug & PRI_DEBUG_APDU) pri_message(pri, "Successfully completed RLT transfer!\n");
|
||||
return 0;
|
||||
case RLT_OPERATION_IND:
|
||||
if (pri->debug & PRI_DEBUG_APDU) pri_message(pri, "Received RLT_OPERATION_IND\n");
|
||||
/* Have to take out the rlt_call_id */
|
||||
GET_COMPONENT(comp, i, vdata, len);
|
||||
CHECK_COMPONENT(comp, ASN1_SEQUENCE, "Protocol error detected in parsing RLT_OPERATION_IND return result!\n");
|
||||
|
||||
/* Traverse the contents of this sequence */
|
||||
/* First is the Operation Value */
|
||||
SUB_COMPONENT(comp, i);
|
||||
GET_COMPONENT(comp, i, vdata, len);
|
||||
CHECK_COMPONENT(comp, ASN1_INTEGER, "RLT_OPERATION_IND should be of type ASN1_INTEGER!\n");
|
||||
ASN1_GET_INTEGER(comp, operationidvalue);
|
||||
|
||||
if (operationidvalue != RLT_OPERATION_IND) {
|
||||
pri_message(pri, "Invalid Operation ID value (0x%x) in return result!\n", operationidvalue);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Next is the Call ID */
|
||||
NEXT_COMPONENT(comp, i);
|
||||
GET_COMPONENT(comp, i, vdata, len);
|
||||
CHECK_COMPONENT(comp, (ASN1_CONTEXT_SPECIFIC|ASN1_TAG_0), "Error check failed on Call ID!\n");
|
||||
ASN1_GET_INTEGER(comp, call->rlt_call_id);
|
||||
/* We have enough data to transfer the call */
|
||||
call->transferable = 1;
|
||||
|
||||
return 0;
|
||||
|
||||
default:
|
||||
pri_message(pri, "Could not parse invoke of type 0x%x!\n", invokeidvalue);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
pri_message(pri, "Unable to handle return result on switchtype %d!\n", pri->switchtype);
|
||||
return -1;
|
||||
}
|
||||
|
||||
} while(0);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern int rose_invoke_decode(struct pri *pri, q931_call *call, unsigned char *data, int len)
|
||||
{
|
||||
int i = 0;
|
||||
@ -1474,6 +1746,12 @@ extern int pri_call_add_standard_apdus(struct pri *pri, q931_call *call)
|
||||
add_callername_facility_ies(pri, call, (pri->localtype == PRI_CPE));
|
||||
#endif
|
||||
|
||||
if ((pri->switchtype == PRI_SWITCH_DMS100) && (pri->localtype == PRI_CPE)) {
|
||||
add_dms100_transfer_ability_apdu(pri, call);
|
||||
}
|
||||
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -104,7 +104,7 @@
|
||||
#define ASN1_CLAN_MASK 0xc0
|
||||
#define ASN1_UNIVERSAL 0x00
|
||||
#define ASN1_APPLICATION 0x40
|
||||
#define ASN1_CONTEXT_SPECIFIC 0x80
|
||||
#define ASN1_CONTEXT_SPECIFIC 0x80
|
||||
#define ASN1_PRIVATE 0xc0
|
||||
|
||||
/* ASN.1 Length masks */
|
||||
@ -135,6 +135,11 @@
|
||||
#define Q932_TON_SUBSCRIBER 0x04
|
||||
#define Q932_TON_ABBREVIATED 0x06
|
||||
|
||||
/* RLT related Operations */
|
||||
#define RLT_SERVICE_ID 0x3e
|
||||
#define RLT_OPERATION_IND 0x01
|
||||
#define RLT_THIRD_PARTY 0x02
|
||||
|
||||
struct rose_component {
|
||||
u_int8_t type;
|
||||
u_int8_t len;
|
||||
@ -230,9 +235,18 @@ struct rose_component {
|
||||
(stack)[(stackpointer)]->len = (unsigned char *)&((data)[(idx)]) - (unsigned char *)(stack)[(stackpointer)] - 2; \
|
||||
} while (0)
|
||||
|
||||
/* Decoder for the invoke part of a ROSE request */
|
||||
/* Decoder for the invoke ROSE component */
|
||||
extern int rose_invoke_decode(struct pri *pri, struct q931_call *call, unsigned char *data, int len);
|
||||
|
||||
/* Decoder for the return result ROSE component */
|
||||
extern int rose_return_result_decode(struct pri *pri, struct q931_call *call, unsigned char *data, int len);
|
||||
|
||||
/* Decoder for the return error ROSE component */
|
||||
extern int rose_return_error_decode(struct pri *pri, struct q931_call *call, unsigned char *data, int len);
|
||||
|
||||
/* Decoder for the reject ROSE component */
|
||||
extern int rose_reject_decode(struct pri *pri, struct q931_call *call, unsigned char *data, int len);
|
||||
|
||||
extern int asn1_copy_string(char * buf, int buflen, struct rose_component *comp);
|
||||
|
||||
extern int asn1_string_encode(unsigned char asn1_type, void *data, int len, int max_len, void *src, int src_len);
|
||||
@ -250,6 +264,8 @@ extern int mwi_message_send(struct pri *pri, q931_call *call, struct pri_sr *req
|
||||
/* starts a 2BCT */
|
||||
extern int eect_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2);
|
||||
|
||||
extern int rlt_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 */
|
||||
|
@ -130,6 +130,7 @@ struct pri_sr {
|
||||
int redirectingreason;
|
||||
int justsignalling;
|
||||
const char *useruserinfo;
|
||||
int transferable;
|
||||
};
|
||||
|
||||
/* Internal switch types */
|
||||
@ -239,6 +240,9 @@ struct q931_call {
|
||||
long aoc_units; /* Advice of Charge Units */
|
||||
|
||||
struct apdu_event *apdus; /* APDU queue for call */
|
||||
|
||||
int transferable;
|
||||
unsigned int rlt_call_id; /* RLT call id */
|
||||
};
|
||||
|
||||
extern int pri_schedule_event(struct pri *pri, int ms, void (*function)(void *data), void *data);
|
||||
|
6
q931.c
6
q931.c
@ -1216,9 +1216,9 @@ static FUNC_RECV(receive_facility)
|
||||
case Q932_PROTOCOL_ROSE:
|
||||
switch (comp->type) {
|
||||
Q932_HANDLE_PROC(COMP_TYPE_INVOKE, Q932_STATE_SERVICE, "ROSE Invoke", rose_invoke_decode);
|
||||
Q932_HANDLE_NULL(COMP_TYPE_RETURN_RESULT, Q932_STATE_SERVICE, "ROSE return result", NULL);
|
||||
Q932_HANDLE_NULL(COMP_TYPE_RETURN_ERROR, Q932_STATE_SERVICE, "ROSE return error", NULL);
|
||||
Q932_HANDLE_NULL(COMP_TYPE_REJECT, Q932_STATE_SERVICE, "ROSE reject", NULL);
|
||||
Q932_HANDLE_PROC(COMP_TYPE_RETURN_RESULT, Q932_STATE_SERVICE, "ROSE return result", rose_return_result_decode);
|
||||
Q932_HANDLE_PROC(COMP_TYPE_RETURN_ERROR, Q932_STATE_SERVICE, "ROSE return error", rose_return_error_decode);
|
||||
Q932_HANDLE_PROC(COMP_TYPE_REJECT, Q932_STATE_SERVICE, "ROSE reject", rose_reject_decode);
|
||||
default:
|
||||
if (pri->debug & PRI_DEBUG_APDU)
|
||||
pri_message(pri, "Don't know how to handle ROSE component of type 0x%X\n", comp->type);
|
||||
|
Loading…
Reference in New Issue
Block a user