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:
Matthew Fredrickson 2006-01-19 18:22:06 +00:00
parent cb7b843e10
commit 0e2e37b537
5 changed files with 309 additions and 8 deletions

9
pri.c
View File

@ -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)

View File

@ -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;
}

View File

@ -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 */

View File

@ -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
View File

@ -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);