Big PRI commit. Merges bugs 3623 and 3554 back. Includes additional
event for Q931_IE_KEYPAD_FACILITY and all of the various Q.SIG functions, 2BCT on 5ESS, and a few other random changes git-svn-id: https://origsvn.digium.com/svn/libpri/trunk@195 2fbb986a-6c06-0410-b554-c9c1f0a7f128
This commit is contained in:
parent
c164cccc87
commit
86cf50b9c3
33
libpri.h
33
libpri.h
@ -46,11 +46,11 @@
|
|||||||
#define PRI_SWITCH_DMS100 2 /* DMS 100 */
|
#define PRI_SWITCH_DMS100 2 /* DMS 100 */
|
||||||
#define PRI_SWITCH_LUCENT5E 3 /* Lucent 5E */
|
#define PRI_SWITCH_LUCENT5E 3 /* Lucent 5E */
|
||||||
#define PRI_SWITCH_ATT4ESS 4 /* AT&T 4ESS */
|
#define PRI_SWITCH_ATT4ESS 4 /* AT&T 4ESS */
|
||||||
#define PRI_SWITCH_EUROISDN_E1 5 /* Standard EuroISDN (CTR4, ETSI 300-102) */
|
#define PRI_SWITCH_EUROISDN_E1 5 /* Standard EuroISDN (CTR4, ETSI 300-102) */
|
||||||
#define PRI_SWITCH_EUROISDN_T1 6 /* T1 EuroISDN variant (ETSI 300-102) */
|
#define PRI_SWITCH_EUROISDN_T1 6 /* T1 EuroISDN variant (ETSI 300-102) */
|
||||||
#define PRI_SWITCH_NI1 7 /* National ISDN 1 */
|
#define PRI_SWITCH_NI1 7 /* National ISDN 1 */
|
||||||
#define PRI_SWITCH_GR303_EOC 8 /* GR-303 Embedded Operations Channel */
|
#define PRI_SWITCH_GR303_EOC 8 /* GR-303 Embedded Operations Channel */
|
||||||
#define PRI_SWITCH_GR303_TMC 9 /* GR-303 Timeslot Management Channel */
|
#define PRI_SWITCH_GR303_TMC 9 /* GR-303 Timeslot Management Channel */
|
||||||
#define PRI_SWITCH_QSIG 10 /* QSIG Switch */
|
#define PRI_SWITCH_QSIG 10 /* QSIG Switch */
|
||||||
/* Switchtypes 10 - 20 are reserved for internal use */
|
/* Switchtypes 10 - 20 are reserved for internal use */
|
||||||
|
|
||||||
@ -73,6 +73,7 @@
|
|||||||
#define PRI_EVENT_HANGUP_REQ 15 /* Requesting the higher layer to hangup */
|
#define PRI_EVENT_HANGUP_REQ 15 /* Requesting the higher layer to hangup */
|
||||||
#define PRI_EVENT_NOTIFY 16 /* Notification received */
|
#define PRI_EVENT_NOTIFY 16 /* Notification received */
|
||||||
#define PRI_EVENT_PROGRESS 17 /* When we get CALL_PROCEEDING or PROGRESS */
|
#define PRI_EVENT_PROGRESS 17 /* When we get CALL_PROCEEDING or PROGRESS */
|
||||||
|
#define PRI_EVENT_KEYPAD_DIGIT 18 /* When we receive during ACTIVE state */
|
||||||
|
|
||||||
/* Simple states */
|
/* Simple states */
|
||||||
#define PRI_STATE_DOWN 0
|
#define PRI_STATE_DOWN 0
|
||||||
@ -347,6 +348,13 @@ typedef struct pri_event_notify {
|
|||||||
int info;
|
int info;
|
||||||
} pri_event_notify;
|
} pri_event_notify;
|
||||||
|
|
||||||
|
typedef struct pri_event_keypad_digit {
|
||||||
|
int e;
|
||||||
|
int channel;
|
||||||
|
q931_call *call;
|
||||||
|
char digits[64];
|
||||||
|
} pri_event_keypad_digit;
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
int e;
|
int e;
|
||||||
pri_event_generic gen; /* Generic view */
|
pri_event_generic gen; /* Generic view */
|
||||||
@ -361,6 +369,7 @@ typedef union {
|
|||||||
pri_event_proceeding proceeding; /* Call proceeding & Progress */
|
pri_event_proceeding proceeding; /* Call proceeding & Progress */
|
||||||
pri_event_setup_ack setup_ack; /* SETUP_ACKNOWLEDGE structure */
|
pri_event_setup_ack setup_ack; /* SETUP_ACKNOWLEDGE structure */
|
||||||
pri_event_notify notify; /* Notification */
|
pri_event_notify notify; /* Notification */
|
||||||
|
pri_event_keypad_digit digit; /* Digits that come during a call */
|
||||||
} pri_event;
|
} pri_event;
|
||||||
|
|
||||||
struct pri;
|
struct pri;
|
||||||
@ -477,7 +486,21 @@ extern int pri_sr_set_caller(struct pri_sr *sr, char *caller, char *callername,
|
|||||||
extern int pri_sr_set_redirecting(struct pri_sr *sr, char *num, int plan, int pres, int reason);
|
extern int pri_sr_set_redirecting(struct pri_sr *sr, char *num, int plan, int pres, int reason);
|
||||||
|
|
||||||
extern int pri_setup(struct pri *pri, q931_call *call, struct pri_sr *req);
|
extern int pri_setup(struct pri *pri, q931_call *call, struct pri_sr *req);
|
||||||
|
|
||||||
|
/* Set a call has a call indpendent signalling connection (i.e. no bchan) */
|
||||||
|
extern 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 */
|
||||||
|
extern 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 */
|
||||||
|
extern int pri_mwi_deactivate(struct pri *pri, q931_call *c, char *caller, int callerplan, char *callername, int callerpres, char *called, int calledplan);
|
||||||
|
|
||||||
|
#define PRI_2BCT
|
||||||
|
/* Attempt to pass the channels back to the NET side if compatable and
|
||||||
|
* suscribed. Sometimes called 2 bchannel transfer (2BCT) */
|
||||||
|
int pri_channel_bridge(q931_call *call1, q931_call *call2);
|
||||||
|
|
||||||
/* Override message and error stuff */
|
/* Override message and error stuff */
|
||||||
extern void pri_set_message(void (*__pri_error)(char *));
|
extern void pri_set_message(void (*__pri_error)(char *));
|
||||||
extern void pri_set_error(void (*__pri_error)(char *));
|
extern void pri_set_error(void (*__pri_error)(char *));
|
||||||
|
108
pri.c
108
pri.c
@ -22,6 +22,7 @@
|
|||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "libpri.h"
|
#include "libpri.h"
|
||||||
#include "pri_internal.h"
|
#include "pri_internal.h"
|
||||||
|
#include "pri_facility.h"
|
||||||
#include "pri_q921.h"
|
#include "pri_q921.h"
|
||||||
#include "pri_q931.h"
|
#include "pri_q931.h"
|
||||||
#include "pri_timers.h"
|
#include "pri_timers.h"
|
||||||
@ -231,6 +232,30 @@ char *pri_event2str(int id)
|
|||||||
return "Restart channel";
|
return "Restart channel";
|
||||||
case PRI_EVENT_RING:
|
case PRI_EVENT_RING:
|
||||||
return "Ring";
|
return "Ring";
|
||||||
|
case PRI_EVENT_HANGUP:
|
||||||
|
return "Hangup";
|
||||||
|
case PRI_EVENT_RINGING:
|
||||||
|
return "Ringing";
|
||||||
|
case PRI_EVENT_ANSWER:
|
||||||
|
return "Answer";
|
||||||
|
case PRI_EVENT_HANGUP_ACK:
|
||||||
|
return "Hangup ACK";
|
||||||
|
case PRI_EVENT_RESTART_ACK:
|
||||||
|
return "Restart ACK";
|
||||||
|
case PRI_EVENT_FACNAME:
|
||||||
|
return "FacName";
|
||||||
|
case PRI_EVENT_INFO_RECEIVED:
|
||||||
|
return "Info Received";
|
||||||
|
case PRI_EVENT_PROCEEDING:
|
||||||
|
return "Proceeding";
|
||||||
|
case PRI_EVENT_SETUP_ACK:
|
||||||
|
return "Setup ACK";
|
||||||
|
case PRI_EVENT_HANGUP_REQ:
|
||||||
|
return "Hangup Req";
|
||||||
|
case PRI_EVENT_NOTIFY:
|
||||||
|
return "Notify";
|
||||||
|
case PRI_EVENT_PROGRESS:
|
||||||
|
return "Progress";
|
||||||
case PRI_EVENT_CONFIG_ERR:
|
case PRI_EVENT_CONFIG_ERR:
|
||||||
return "Configuration Error";
|
return "Configuration Error";
|
||||||
default:
|
default:
|
||||||
@ -399,6 +424,28 @@ int pri_disconnect(struct pri *pri, q931_call *call, int cause)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
int pri_channel_bridge(q931_call *call1, q931_call *call2)
|
||||||
|
{
|
||||||
|
if (!call1 || !call2)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Check switchtype compatibility */
|
||||||
|
if (call1->pri->switchtype != PRI_SWITCH_LUCENT5E ||
|
||||||
|
call2->pri->switchtype != PRI_SWITCH_LUCENT5E)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Check to see if calls are on the same PRI dchannel
|
||||||
|
* Currently only support calls on the same dchannel
|
||||||
|
*/
|
||||||
|
if (call1->pri != call2->pri)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (eect_initiate_transfer(call1->pri, call1, call2))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int pri_hangup(struct pri *pri, q931_call *call, int cause)
|
int pri_hangup(struct pri *pri, q931_call *call, int cause)
|
||||||
{
|
{
|
||||||
if (!pri || !call)
|
if (!pri || !call)
|
||||||
@ -456,10 +503,71 @@ static void pri_sr_init(struct pri_sr *req)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int pri_sr_set_connection_call_independent(struct pri_sr *req)
|
||||||
|
{
|
||||||
|
if (!req)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
req->justsignalling = 1; /* have to set justsignalling for all those pesky IEs we need to setup */
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
struct pri_sr req;
|
||||||
|
if (!pri || !c)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
pri_sr_init(&req);
|
||||||
|
pri_sr_set_connection_call_independent(&req);
|
||||||
|
|
||||||
|
req.caller = caller;
|
||||||
|
req.callerplan = callerplan;
|
||||||
|
req.callername = callername;
|
||||||
|
req.callerpres = callerpres;
|
||||||
|
req.called = called;
|
||||||
|
req.calledplan = calledplan;
|
||||||
|
|
||||||
|
if (mwi_message_send(pri, c, &req, 1) < 0) {
|
||||||
|
pri_message("Unable to send MWI activate message\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* Do more stuff when we figure out that the CISC stuff works */
|
||||||
|
return q931_setup(pri, c, &req);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pri_mwi_deactivate(struct pri *pri, q931_call *c, char *caller, int callerplan, char *callername, int callerpres, char *called,
|
||||||
|
int calledplan)
|
||||||
|
{
|
||||||
|
struct pri_sr req;
|
||||||
|
if (!pri || !c)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
pri_sr_init(&req);
|
||||||
|
pri_sr_set_connection_call_independent(&req);
|
||||||
|
|
||||||
|
req.caller = caller;
|
||||||
|
req.callerplan = callerplan;
|
||||||
|
req.callername = callername;
|
||||||
|
req.callerpres = callerpres;
|
||||||
|
req.called = called;
|
||||||
|
req.calledplan = calledplan;
|
||||||
|
|
||||||
|
if(mwi_message_send(pri, c, &req, 0) < 0) {
|
||||||
|
pri_message("Unable to send MWI deactivate message\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return q931_setup(pri, c, &req);
|
||||||
|
}
|
||||||
|
|
||||||
int pri_setup(struct pri *pri, q931_call *c, struct pri_sr *req)
|
int pri_setup(struct pri *pri, q931_call *c, struct pri_sr *req)
|
||||||
{
|
{
|
||||||
if (!pri || !c)
|
if (!pri || !c)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return q931_setup(pri, c, req);
|
return q931_setup(pri, c, req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
484
pri_facility.c
484
pri_facility.c
@ -1,9 +1,12 @@
|
|||||||
/*
|
/*
|
||||||
|
This file and it's contents are licensed under the terms and conditions
|
||||||
|
of the GNU Public License. See http://www.gnu.org for details.
|
||||||
|
|
||||||
Routines for dealing with facility messages and their respective
|
Routines for dealing with facility messages and their respective
|
||||||
components (ROSE)
|
components (ROSE)
|
||||||
|
|
||||||
by Matthew Fredrickson <creslin@digium.com>
|
by Matthew Fredrickson <creslin@digium.com>
|
||||||
Copyright (C) 2004 Digium, Inc
|
Copyright (C) 2004-2005 Digium, Inc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
@ -18,9 +21,14 @@
|
|||||||
|
|
||||||
#undef DEBUG
|
#undef DEBUG
|
||||||
|
|
||||||
|
static unsigned char get_invokeid(struct pri *pri)
|
||||||
|
{
|
||||||
|
return ++pri->last_invoke;
|
||||||
|
}
|
||||||
|
|
||||||
struct addressingdataelements_presentednumberunscreened {
|
struct addressingdataelements_presentednumberunscreened {
|
||||||
char partyAddress[21];
|
char partyaddress[21];
|
||||||
char partySubaddress[21];
|
char partysubaddress[21];
|
||||||
int npi;
|
int npi;
|
||||||
int ton;
|
int ton;
|
||||||
int pres;
|
int pres;
|
||||||
@ -182,8 +190,8 @@ static int rose_number_digits_decode(struct pri *pri, q931_call *call, unsigned
|
|||||||
pri_message("!! Oversized NumberDigits component (%d)\n", comp->len);
|
pri_message("!! Oversized NumberDigits component (%d)\n", comp->len);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
memcpy(value->partyAddress, comp->data, comp->len);
|
memcpy(value->partyaddress, comp->data, comp->len);
|
||||||
value->partyAddress[comp->len] = '\0';
|
value->partyaddress[comp->len] = '\0';
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -331,8 +339,8 @@ static int rose_diverting_leg_information2_decode(struct pri *pri, q931_call *ca
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
int diversion_counter;
|
int diversion_counter;
|
||||||
int diversion_reason;
|
int diversion_reason;
|
||||||
struct addressingdataelements_presentednumberunscreened divertingNr;
|
struct addressingdataelements_presentednumberunscreened divertingnr;
|
||||||
struct addressingdataelements_presentednumberunscreened originalCalledNr;
|
struct addressingdataelements_presentednumberunscreened originalcallednr;
|
||||||
struct rose_component *comp = NULL;
|
struct rose_component *comp = NULL;
|
||||||
unsigned char *vdata = data;
|
unsigned char *vdata = data;
|
||||||
|
|
||||||
@ -359,23 +367,23 @@ static int rose_diverting_leg_information2_decode(struct pri *pri, q931_call *ca
|
|||||||
for(; i < len; NEXT_COMPONENT(comp, i)) {
|
for(; i < len; NEXT_COMPONENT(comp, i)) {
|
||||||
GET_COMPONENT(comp, i, vdata, len);
|
GET_COMPONENT(comp, i, vdata, len);
|
||||||
switch(comp->type) {
|
switch(comp->type) {
|
||||||
case 0xA1: /* divertingNr: PresentedNumberUnscreened */
|
case 0xA1: /* divertingnr: presentednumberunscreened */
|
||||||
if(rose_presented_number_unscreened_decode(pri, call, comp->data, comp->len, &divertingNr) != 0)
|
if(rose_presented_number_unscreened_decode(pri, call, comp->data, comp->len, &divertingnr) != 0)
|
||||||
return -1;
|
return -1;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (pri->debug) {
|
if (pri->debug) {
|
||||||
pri_message(" Received divertingNr '%s'\n", divertingNr.partyAddress);
|
pri_message(" Received divertingNr '%s'\n", divertingnr.partyaddress);
|
||||||
pri_message(" ton = %d, pres = %d, npi = %d\n", divertingNr.ton, divertingNr.pres, divertingNr.npi);
|
pri_message(" ton = %d, pres = %d, npi = %d\n", divertingnr.ton, divertingnr.pres, divertingnr.npi);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
case 0xA2: /* originalCalledNr: PresentedNumberUnscreened */
|
case 0xA2: /* originalCalledNr: PresentedNumberUnscreened */
|
||||||
if(rose_presented_number_unscreened_decode(pri, call, comp->data, comp->len, &originalCalledNr) != 0)
|
if(rose_presented_number_unscreened_decode(pri, call, comp->data, comp->len, &originalcallednr) != 0)
|
||||||
return -1;
|
return -1;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (pri->debug) {
|
if (pri->debug) {
|
||||||
pri_message(" Received originalCalledNr '%s'\n", originalCalledNr.partyAddress);
|
pri_message(" Received originalcallednr '%s'\n", originalcallednr.partyaddress);
|
||||||
pri_message(" ton = %d, pres = %d, npi = %d\n", originalCalledNr.ton, originalCalledNr.pres, originalCalledNr.npi);
|
pri_message(" ton = %d, pres = %d, npi = %d\n", originalcallednr.ton, originalcallednr.pres, originalcallednr.npi);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
@ -387,18 +395,18 @@ static int rose_diverting_leg_information2_decode(struct pri *pri, q931_call *ca
|
|||||||
if (i < len)
|
if (i < len)
|
||||||
return -1; /* Aborted before */
|
return -1; /* Aborted before */
|
||||||
|
|
||||||
if (divertingNr.pres >= 0) {
|
if (divertingnr.pres >= 0) {
|
||||||
call->redirectingplan = divertingNr.npi;
|
call->redirectingplan = divertingnr.npi;
|
||||||
call->redirectingpres = divertingNr.pres;
|
call->redirectingpres = divertingnr.pres;
|
||||||
call->redirectingreason = diversion_reason;
|
call->redirectingreason = diversion_reason;
|
||||||
strncpy(call->redirectingnum, divertingNr.partyAddress, sizeof(call->redirectingnum)-1);
|
strncpy(call->redirectingnum, divertingnr.partyaddress, sizeof(call->redirectingnum)-1);
|
||||||
call->redirectingnum[sizeof(call->redirectingnum)-1] = '\0';
|
call->redirectingnum[sizeof(call->redirectingnum)-1] = '\0';
|
||||||
}
|
}
|
||||||
else if (originalCalledNr.pres >= 0) {
|
else if (originalcallednr.pres >= 0) {
|
||||||
call->redirectingplan = originalCalledNr.npi;
|
call->redirectingplan = originalcallednr.npi;
|
||||||
call->redirectingpres = originalCalledNr.pres;
|
call->redirectingpres = originalcallednr.pres;
|
||||||
call->redirectingreason = diversion_reason;
|
call->redirectingreason = diversion_reason;
|
||||||
strncpy(call->redirectingnum, originalCalledNr.partyAddress, sizeof(call->redirectingnum)-1);
|
strncpy(call->redirectingnum, originalcallednr.partyaddress, sizeof(call->redirectingnum)-1);
|
||||||
call->redirectingnum[sizeof(call->redirectingnum)-1] = '\0';
|
call->redirectingnum[sizeof(call->redirectingnum)-1] = '\0';
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -408,7 +416,364 @@ static int rose_diverting_leg_information2_decode(struct pri *pri, q931_call *ca
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rose_invoke_decode(struct pri *pri, q931_call *call, unsigned char *data, int len)
|
static int rose_diverting_leg_information2_encode(struct pri *pri, q931_call *call)
|
||||||
|
{
|
||||||
|
int i = 0, j, compsp = 0;
|
||||||
|
struct rose_component *comp, *compstk[10];
|
||||||
|
unsigned char buffer[256];
|
||||||
|
int len = 253;
|
||||||
|
|
||||||
|
if (!strlen(call->callername)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[i] = 0x80 | Q932_PROTOCOL_EXTENSIONS;
|
||||||
|
i++;
|
||||||
|
/* Interpretation component */
|
||||||
|
ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0x00 /* Discard unrecognized invokes */);
|
||||||
|
|
||||||
|
ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
|
||||||
|
|
||||||
|
ASN1_PUSH(compstk, compsp, comp);
|
||||||
|
/* Invoke component contents */
|
||||||
|
/* Invoke ID */
|
||||||
|
ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri));
|
||||||
|
/* Operation Tag */
|
||||||
|
|
||||||
|
/* ROSE operationId component */
|
||||||
|
ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, ROSE_DIVERTING_LEG_INFORMATION2);
|
||||||
|
|
||||||
|
/* ROSE ARGUMENT component */
|
||||||
|
ASN1_ADD_SIMPLE(comp, 0x30, buffer, i);
|
||||||
|
ASN1_PUSH(compstk, compsp, comp);
|
||||||
|
/* ROSE DivertingLegInformation2.diversionCounter component */
|
||||||
|
/* Always is 1 because other isn't available in the current design */
|
||||||
|
ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, 1);
|
||||||
|
|
||||||
|
/* ROSE DivertingLegInformation2.diversionReason component */
|
||||||
|
ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, redirectingreason_from_q931(pri, call->redirectingreason));
|
||||||
|
|
||||||
|
/* ROSE DivertingLegInformation2.divertingNr component */
|
||||||
|
ASN1_ADD_SIMPLE(comp, 0xA1, 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, 0xA0, buffer, i);
|
||||||
|
ASN1_PUSH(compstk, compsp, comp);
|
||||||
|
/* NPI of redirected number is not supported in the current design */
|
||||||
|
ASN1_ADD_SIMPLE(comp, 0xA1, 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, 0x81, 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, 0x81, buffer, i);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pri_message("!! Undefined presentation value for redirecting number: %d\n", call->redirectingpres);
|
||||||
|
case PRES_NUMBER_NOT_AVAILABLE:
|
||||||
|
ASN1_ADD_SIMPLE(comp, 0x82, buffer, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ASN1_FIXUP(compstk, compsp, buffer, i);
|
||||||
|
|
||||||
|
/* ROSE DivertingLegInformation2.originalCalledNr component */
|
||||||
|
/* This information isn't supported by current design - duplicate divertingNr */
|
||||||
|
ASN1_ADD_SIMPLE(comp, 0xA2, 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, 0xA0, buffer, i);
|
||||||
|
ASN1_PUSH(compstk, compsp, comp);
|
||||||
|
ASN1_ADD_SIMPLE(comp, 0xA1, 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, 0x81, 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, 0x81, buffer, i);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pri_message("!! Undefined presentation value for redirecting number: %d\n", call->redirectingpres);
|
||||||
|
case PRES_NUMBER_NOT_AVAILABLE:
|
||||||
|
ASN1_ADD_SIMPLE(comp, 0x82, buffer, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ASN1_FIXUP(compstk, compsp, buffer, i);
|
||||||
|
|
||||||
|
/* Fix length of stacked components */
|
||||||
|
while(compsp > 0) {
|
||||||
|
ASN1_FIXUP(compstk, compsp, buffer, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pri_call_apdu_queue(call, Q931_SETUP, buffer, i, NULL, NULL))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sending callername information functions */
|
||||||
|
static int add_callername_facility_ies(struct pri *pri, q931_call *c)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
int i = 0;
|
||||||
|
unsigned char buffer[256];
|
||||||
|
unsigned char namelen = 0;
|
||||||
|
struct rose_component *comp = NULL, *compstk[10];
|
||||||
|
int compsp = 0;
|
||||||
|
static unsigned char op_tag[] = {
|
||||||
|
0x2a, /* informationFollowing 42 */
|
||||||
|
0x86,
|
||||||
|
0x48,
|
||||||
|
0xce,
|
||||||
|
0x15,
|
||||||
|
0x00,
|
||||||
|
0x04
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!strlen(c->callername)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[i++] = 0x80 | Q932_PROTOCOL_EXTENSIONS;
|
||||||
|
/* Interpretation component */
|
||||||
|
|
||||||
|
ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i);
|
||||||
|
ASN1_PUSH(compstk, compsp, comp);
|
||||||
|
ASN1_ADD_BYTECOMP(comp, 0x80, buffer, i, 0);
|
||||||
|
ASN1_ADD_BYTECOMP(comp, 0x82, buffer, i, 0);
|
||||||
|
ASN1_FIXUP(compstk, compsp, buffer, i);
|
||||||
|
|
||||||
|
ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0);
|
||||||
|
|
||||||
|
ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
|
||||||
|
ASN1_PUSH(compstk, compsp, comp);
|
||||||
|
/* Invoke ID */
|
||||||
|
ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri));
|
||||||
|
|
||||||
|
/* Operation Tag */
|
||||||
|
res = asn1_string_encode(ASN1_OBJECTIDENTIFIER, &buffer[i], sizeof(buffer)-i, sizeof(op_tag), op_tag, sizeof(op_tag));
|
||||||
|
if (res < 0)
|
||||||
|
return -1;
|
||||||
|
i += res;
|
||||||
|
|
||||||
|
ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 0);
|
||||||
|
ASN1_FIXUP(compstk, compsp, buffer, i);
|
||||||
|
|
||||||
|
if (pri_call_apdu_queue(c, Q931_SETUP, buffer, i, NULL, NULL))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
|
||||||
|
/* Now the ADPu that contains the information that needs sent.
|
||||||
|
* We can reuse the buffer since the queue function doesn't
|
||||||
|
* need it. */
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
namelen = strlen(c->callername);
|
||||||
|
if (namelen > 50) {
|
||||||
|
namelen = 50; /* truncate the name */
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[i++] = 0x80 | Q932_PROTOCOL_EXTENSIONS;
|
||||||
|
/* Interpretation component */
|
||||||
|
|
||||||
|
ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i);
|
||||||
|
ASN1_PUSH(compstk, compsp, comp);
|
||||||
|
ASN1_ADD_BYTECOMP(comp, 0x80, buffer, i, 0);
|
||||||
|
ASN1_ADD_BYTECOMP(comp, 0x82, buffer, i, 0);
|
||||||
|
ASN1_FIXUP(compstk, compsp, buffer, i);
|
||||||
|
|
||||||
|
ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0);
|
||||||
|
|
||||||
|
ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
|
||||||
|
ASN1_PUSH(compstk, compsp, comp);
|
||||||
|
|
||||||
|
/* Invoke ID */
|
||||||
|
ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri));
|
||||||
|
|
||||||
|
/* Operation ID: Calling name */
|
||||||
|
ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, SS_CNID_CALLINGNAME);
|
||||||
|
|
||||||
|
res = asn1_string_encode(0x80, &buffer[i], sizeof(buffer)-i, 50, c->callername, namelen);
|
||||||
|
if (res < 0)
|
||||||
|
return -1;
|
||||||
|
i += res;
|
||||||
|
ASN1_FIXUP(compstk, compsp, buffer, i);
|
||||||
|
|
||||||
|
if (pri_call_apdu_queue(c, Q931_FACILITY, buffer, i, NULL, NULL))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* End Callername */
|
||||||
|
|
||||||
|
/* MWI related encode and decode functions */
|
||||||
|
static void mwi_activate_encode_cb(void *data)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern int mwi_message_send(struct pri* pri, q931_call *call, struct pri_sr *req, int activate)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
unsigned char buffer[255] = "";
|
||||||
|
int destlen = strlen(req->called);
|
||||||
|
struct rose_component *comp = NULL, *compstk[10];
|
||||||
|
int compsp = 0;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if (destlen <= 0) {
|
||||||
|
return -1;
|
||||||
|
} else if (destlen > 20)
|
||||||
|
destlen = 20; /* Destination number cannot be greater then 20 digits */
|
||||||
|
|
||||||
|
buffer[i++] = 0x80 | Q932_PROTOCOL_EXTENSIONS;
|
||||||
|
/* Interpretation component */
|
||||||
|
|
||||||
|
ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i);
|
||||||
|
ASN1_PUSH(compstk, compsp, comp);
|
||||||
|
ASN1_ADD_BYTECOMP(comp, 0x80, buffer, i, 0);
|
||||||
|
ASN1_ADD_BYTECOMP(comp, 0x82, buffer, i, 0);
|
||||||
|
ASN1_FIXUP(compstk, compsp, buffer, i);
|
||||||
|
|
||||||
|
ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0);
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, (activate) ? SS_MWI_ACTIVATE : SS_MWI_DEACTIVATE);
|
||||||
|
ASN1_ADD_SIMPLE(comp, 0x30 /* Sequence */, buffer, i);
|
||||||
|
ASN1_PUSH(compstk, compsp, comp);
|
||||||
|
/* PartyNumber */
|
||||||
|
res = asn1_string_encode(0x80, &buffer[i], sizeof(buffer)-i, destlen, req->called, destlen);
|
||||||
|
|
||||||
|
if (res < 0)
|
||||||
|
return -1;
|
||||||
|
i += res;
|
||||||
|
|
||||||
|
/* Enumeration: basicService */
|
||||||
|
ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 1 /* contents: Voice */);
|
||||||
|
ASN1_FIXUP(compstk, compsp, buffer, i);
|
||||||
|
ASN1_FIXUP(compstk, compsp, buffer, i);
|
||||||
|
|
||||||
|
return pri_call_apdu_queue(call, Q931_SETUP, buffer, i, mwi_activate_encode_cb, NULL);
|
||||||
|
}
|
||||||
|
/* End MWI */
|
||||||
|
|
||||||
|
/* EECT functions */
|
||||||
|
extern int eect_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[] = {
|
||||||
|
0x2A,
|
||||||
|
0x86,
|
||||||
|
0x48,
|
||||||
|
0xCE,
|
||||||
|
0x15,
|
||||||
|
0x00,
|
||||||
|
0x08,
|
||||||
|
};
|
||||||
|
|
||||||
|
buffer[i++] = 0x80 | Q932_PROTOCOL_EXTENSIONS;
|
||||||
|
/* Interpretation component */
|
||||||
|
|
||||||
|
ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i);
|
||||||
|
ASN1_PUSH(compstk, compsp, comp);
|
||||||
|
ASN1_ADD_BYTECOMP(comp, 0x80, buffer, i, 0);
|
||||||
|
ASN1_ADD_BYTECOMP(comp, 0x82, buffer, i, 0);
|
||||||
|
ASN1_FIXUP(compstk, compsp, buffer, i);
|
||||||
|
|
||||||
|
ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0);
|
||||||
|
|
||||||
|
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_OBJECTIDENTIFIER, &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 | 0x20, buffer, i);
|
||||||
|
ASN1_PUSH(compstk, compsp, comp);
|
||||||
|
ASN1_ADD_WORDCOMP(comp, 0x02, 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("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("Could not schedule facility message for call %d\n", c1->cr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* End EECT */
|
||||||
|
|
||||||
|
|
||||||
|
extern int rose_invoke_decode(struct pri *pri, q931_call *call, unsigned char *data, int len)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int operation_tag;
|
int operation_tag;
|
||||||
@ -480,3 +845,76 @@ int rose_invoke_decode(struct pri *pri, q931_call *call, unsigned char *data, in
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern int pri_call_apdu_queue(q931_call *call, int messagetype, void *apdu, int apdu_len, void (*function)(void *data), void *data)
|
||||||
|
{
|
||||||
|
struct apdu_event *cur = NULL;
|
||||||
|
struct apdu_event *new_event = NULL;
|
||||||
|
|
||||||
|
if (!call || !messagetype || !apdu || (apdu_len < 1) || (apdu_len > 255))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
new_event = malloc(sizeof(struct apdu_event));
|
||||||
|
memset(new_event, 0, sizeof(struct apdu_event));
|
||||||
|
|
||||||
|
if (new_event) {
|
||||||
|
new_event->message = messagetype;
|
||||||
|
new_event->callback = function;
|
||||||
|
new_event->data = data;
|
||||||
|
memcpy(new_event->apdu, apdu, apdu_len);
|
||||||
|
new_event->apdu_len = apdu_len;
|
||||||
|
} else {
|
||||||
|
pri_error("malloc failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (call->apdus) {
|
||||||
|
cur = call->apdus;
|
||||||
|
while (cur->next) {
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
|
cur->next = new_event;
|
||||||
|
} else
|
||||||
|
call->apdus = new_event;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern int pri_call_apdu_queue_cleanup(q931_call *call)
|
||||||
|
{
|
||||||
|
struct apdu_event *cur_event = NULL, *free_event = NULL;
|
||||||
|
|
||||||
|
if (call && call->apdus) {
|
||||||
|
cur_event = call->apdus;
|
||||||
|
while (cur_event) {
|
||||||
|
/* TODO: callbacks, some way of giving return res on status of apdu */
|
||||||
|
free_event = cur_event;
|
||||||
|
free(free_event);
|
||||||
|
cur_event = cur_event->next;
|
||||||
|
}
|
||||||
|
call->apdus = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern int pri_call_add_standard_apdus(struct pri *pri, q931_call *call)
|
||||||
|
{
|
||||||
|
if (pri->switchtype == PRI_SWITCH_QSIG) { /* For Q.SIG it does network and cpe operations */
|
||||||
|
rose_diverting_leg_information2_encode(pri, call);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if (pri->localtype == PRI_NETWORK) {
|
||||||
|
#endif
|
||||||
|
if (1) {
|
||||||
|
switch (pri->switchtype) {
|
||||||
|
case PRI_SWITCH_NI2:
|
||||||
|
add_callername_facility_ies(pri, call);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
within those messages.
|
within those messages.
|
||||||
|
|
||||||
by Matthew Fredrickson <creslin@digium.com>
|
by Matthew Fredrickson <creslin@digium.com>
|
||||||
Copyright (C) Digium, Inc. 2004
|
Copyright (C) Digium, Inc. 2004-2005
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _PRI_FACILITY_H
|
#ifndef _PRI_FACILITY_H
|
||||||
@ -134,38 +134,80 @@ struct rose_component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define ASN1_GET_INTEGER(component, variable) \
|
#define ASN1_GET_INTEGER(component, variable) \
|
||||||
{ \
|
do { \
|
||||||
int comp_idx; \
|
int comp_idx; \
|
||||||
(variable) = 0; \
|
(variable) = 0; \
|
||||||
for (comp_idx = 0; comp_idx < (component)->len; ++comp_idx) \
|
for (comp_idx = 0; comp_idx < (component)->len; ++comp_idx) \
|
||||||
(variable) = ((variable) << 8) | (component)->data[comp_idx]; \
|
(variable) = ((variable) << 8) | (component)->data[comp_idx]; \
|
||||||
}
|
} while (0)
|
||||||
|
|
||||||
#define ASN1_ADD_SIMPLE(component, comptype, ptr, idx) \
|
#define ASN1_ADD_SIMPLE(component, comptype, ptr, idx) \
|
||||||
(component) = (struct rose_component *)&((ptr)[(idx)]); \
|
do { \
|
||||||
(component)->type = (comptype); \
|
(component) = (struct rose_component *)&((ptr)[(idx)]); \
|
||||||
(component)->len = 0; \
|
(component)->type = (comptype); \
|
||||||
(idx) += 2;
|
(component)->len = 0; \
|
||||||
|
(idx) += 2; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define ASN1_ADD_BYTECOMP(component, comptype, ptr, idx, value) \
|
#define ASN1_ADD_BYTECOMP(component, comptype, ptr, idx, value) \
|
||||||
(component) = (struct rose_component *)&((ptr)[(idx)]); \
|
do { \
|
||||||
(component)->type = (comptype); \
|
(component) = (struct rose_component *)&((ptr)[(idx)]); \
|
||||||
(component)->len = 1; \
|
(component)->type = (comptype); \
|
||||||
(component)->data[0] = (value); \
|
(component)->len = 1; \
|
||||||
(idx) += 3;
|
(component)->data[0] = (value); \
|
||||||
|
(idx) += 3; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define ASN1_ADD_WORDCOMP(component, comptype, ptr, idx, value) \
|
||||||
|
do { \
|
||||||
|
int __val = (value); \
|
||||||
|
int __i = 0; \
|
||||||
|
(component) = (struct rose_component *)&((ptr)[(idx)]); \
|
||||||
|
(component)->type = (comptype); \
|
||||||
|
if ((__val >> 24)) \
|
||||||
|
(component)->data[__i++] = (__val >> 24) & 0xff; \
|
||||||
|
if ((__val >> 16)) \
|
||||||
|
(component)->data[__i++] = (__val >> 16) & 0xff; \
|
||||||
|
if ((__val >> 8)) \
|
||||||
|
(component)->data[__i++] = (__val >> 8) & 0xff; \
|
||||||
|
(component)->data[__i++] = __val & 0xff; \
|
||||||
|
(component)->len = __i; \
|
||||||
|
(idx) += 2 + __i; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define ASN1_PUSH(stack, stackpointer, component) \
|
#define ASN1_PUSH(stack, stackpointer, component) \
|
||||||
(stack)[(stackpointer)++] = (component);
|
(stack)[(stackpointer)++] = (component)
|
||||||
|
|
||||||
#define ASN1_FIXUP(stack, stackpointer, data, idx) \
|
#define ASN1_FIXUP(stack, stackpointer, data, idx) \
|
||||||
--(stackpointer); \
|
do { \
|
||||||
(stack)[(stackpointer)]->len = (unsigned char *)&((data)[(idx)]) - (unsigned char *)(stack)[(stackpointer)] - 2;
|
--(stackpointer); \
|
||||||
|
(stack)[(stackpointer)]->len = (unsigned char *)&((data)[(idx)]) - (unsigned char *)(stack)[(stackpointer)] - 2; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
/* Decoder fo the invoke part of a ROSE request
|
/* Decoder for the invoke part of a ROSE request */
|
||||||
It currently only support calling name decode */
|
|
||||||
extern int rose_invoke_decode(struct pri *pri, struct q931_call *call, unsigned char *data, int len);
|
extern int rose_invoke_decode(struct pri *pri, struct q931_call *call, unsigned char *data, int len);
|
||||||
|
|
||||||
extern int asn1_string_encode(unsigned char asn1_type, void *data, int len, int max_len, void *src, int src_len);
|
extern int asn1_string_encode(unsigned char asn1_type, void *data, int len, int max_len, void *src, int src_len);
|
||||||
int typeofnumber_from_q931(struct pri *pri, int ton);
|
|
||||||
int redirectingreason_from_q931(struct pri *pri, int redirectingreason);
|
extern int typeofnumber_from_q931(struct pri *pri, int ton);
|
||||||
|
|
||||||
|
extern int redirectingreason_from_q931(struct pri *pri, int redirectingreason);
|
||||||
|
|
||||||
|
/* Queues an MWI apdu on a the given call */
|
||||||
|
extern int mwi_message_send(struct pri *pri, q931_call *call, struct pri_sr *req, int activate);
|
||||||
|
|
||||||
|
/* starts a 2BCT */
|
||||||
|
extern int eect_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2);
|
||||||
|
|
||||||
|
/* Use this function to queue a facility-IE born ADPU 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 */
|
||||||
|
extern int pri_call_apdu_queue(q931_call *call, int messagetype, void *apdu, int apdu_len, void (*function)(void *data), void *data);
|
||||||
|
|
||||||
|
/* Used by q931.c to cleanup the apdu queue upon destruction of a call */
|
||||||
|
extern int pri_call_apdu_queue_cleanup(q931_call *call);
|
||||||
|
|
||||||
|
/* Adds the "standard" ADPUs to a call */
|
||||||
|
extern int pri_call_add_standard_apdus(struct pri *pri, q931_call *call);
|
||||||
|
|
||||||
#endif /* _PRI_FACILITY_H */
|
#endif /* _PRI_FACILITY_H */
|
||||||
|
@ -124,11 +124,22 @@ struct pri_sr {
|
|||||||
int redirectingplan;
|
int redirectingplan;
|
||||||
int redirectingpres;
|
int redirectingpres;
|
||||||
int redirectingreason;
|
int redirectingreason;
|
||||||
|
int justsignalling;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Internal switch types */
|
/* Internal switch types */
|
||||||
#define PRI_SWITCH_GR303_EOC_PATH 10
|
#define PRI_SWITCH_GR303_EOC_PATH 19
|
||||||
#define PRI_SWITCH_GR303_TMC_SWITCHING 11
|
#define PRI_SWITCH_GR303_TMC_SWITCHING 20
|
||||||
|
|
||||||
|
struct apdu_event {
|
||||||
|
int message; /* What message to send the ADPU in */
|
||||||
|
void (*callback)(void *data); /* Callback function for when response is received */
|
||||||
|
void *data; /* Data to callback */
|
||||||
|
unsigned char apdu[255]; /* ADPU to send */
|
||||||
|
int apdu_len; /* Length of ADPU */
|
||||||
|
int sent; /* Have we been sent already? */
|
||||||
|
struct apdu_event *next; /* Linked list pointer */
|
||||||
|
};
|
||||||
|
|
||||||
/* q931_call datastructure */
|
/* q931_call datastructure */
|
||||||
|
|
||||||
@ -163,6 +174,7 @@ struct q931_call {
|
|||||||
int rateadaption;
|
int rateadaption;
|
||||||
|
|
||||||
int sentchannel;
|
int sentchannel;
|
||||||
|
int justsignalling; /* for a signalling-only connection */
|
||||||
|
|
||||||
int progcode; /* Progress coding */
|
int progcode; /* Progress coding */
|
||||||
int progloc; /* Progress Location */
|
int progloc; /* Progress Location */
|
||||||
@ -184,6 +196,8 @@ struct q931_call {
|
|||||||
char callernum[256]; /* Caller */
|
char callernum[256]; /* Caller */
|
||||||
char callername[256];
|
char callername[256];
|
||||||
|
|
||||||
|
char digitbuf[64]; /* Buffer for digits that come in KEYPAD_FACILITY */
|
||||||
|
|
||||||
int ani2; /* ANI II */
|
int ani2; /* ANI II */
|
||||||
|
|
||||||
int calledplan;
|
int calledplan;
|
||||||
@ -202,6 +216,8 @@ struct q931_call {
|
|||||||
int useruserprotocoldisc;
|
int useruserprotocoldisc;
|
||||||
char useruserinfo[256];
|
char useruserinfo[256];
|
||||||
char callingsubaddr[256]; /* Calling parties sub address */
|
char callingsubaddr[256]; /* Calling parties sub address */
|
||||||
|
|
||||||
|
struct apdu_event *apdus; /* APDU queue for call */
|
||||||
};
|
};
|
||||||
|
|
||||||
extern int pri_schedule_event(struct pri *pri, int ms, void (*function)(void *data), void *data);
|
extern int pri_schedule_event(struct pri *pri, int ms, void (*function)(void *data), void *data);
|
||||||
|
@ -267,6 +267,8 @@ extern int q931_hangup(struct pri *pri, q931_call *call, int cause);
|
|||||||
|
|
||||||
extern int q931_restart(struct pri *pri, int channel);
|
extern int q931_restart(struct pri *pri, int channel);
|
||||||
|
|
||||||
|
extern int q931_facility(struct pri *pri, q931_call *call);
|
||||||
|
|
||||||
extern int q931_call_getcrv(struct pri *pri, q931_call *call, int *callmode);
|
extern int q931_call_getcrv(struct pri *pri, q931_call *call, int *callmode);
|
||||||
|
|
||||||
extern int q931_call_setcrv(struct pri *pri, q931_call *call, int crv, int callmode);
|
extern int q931_call_setcrv(struct pri *pri, q931_call *call, int crv, int callmode);
|
||||||
|
152
q931.c
152
q931.c
@ -277,9 +277,15 @@ static FUNC_RECV(receive_channel_id)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifndef NOAUTO_CHANNEL_SELECTION_SUPPORT
|
#ifndef NOAUTO_CHANNEL_SELECTION_SUPPORT
|
||||||
if ((ie->data[0] & 3) != 1) {
|
switch (ie->data[0] & 3) {
|
||||||
pri_error("!! Unexpected Channel selection %d\n", ie->data[0] & 3);
|
case 0:
|
||||||
return -1;
|
call->justsignalling = 1;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pri_error("!! Unexpected Channel selection %d\n", ie->data[0] & 3);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (ie->data[0] & 0x08)
|
if (ie->data[0] & 0x08)
|
||||||
@ -326,10 +332,17 @@ static FUNC_SEND(transmit_channel_id)
|
|||||||
{
|
{
|
||||||
int pos=0;
|
int pos=0;
|
||||||
|
|
||||||
|
|
||||||
/* We are ready to transmit single IE only */
|
/* We are ready to transmit single IE only */
|
||||||
if (order > 1)
|
if (order > 1)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (call->justsignalling) {
|
||||||
|
ie->data[pos++] = 0xac; /* Read the standards docs to figure this out
|
||||||
|
ECMA-165 section 7.3 */
|
||||||
|
return pos + 2;
|
||||||
|
}
|
||||||
|
|
||||||
/* Start with standard stuff */
|
/* Start with standard stuff */
|
||||||
if (pri->switchtype == PRI_SWITCH_GR303_TMC)
|
if (pri->switchtype == PRI_SWITCH_GR303_TMC)
|
||||||
ie->data[pos] = 0x69;
|
ie->data[pos] = 0x69;
|
||||||
@ -615,6 +628,13 @@ static FUNC_SEND(transmit_bearer_capability)
|
|||||||
ie->data[1] = 0x90;
|
ie->data[1] = 0x90;
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (call->justsignalling) {
|
||||||
|
ie->data[0] = 0xa8;
|
||||||
|
ie->data[1] = 0x80;
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
if (pri->switchtype == PRI_SWITCH_ATT4ESS) {
|
if (pri->switchtype == PRI_SWITCH_ATT4ESS) {
|
||||||
/* 4ESS uses a different trans capability for 3.1khz audio */
|
/* 4ESS uses a different trans capability for 3.1khz audio */
|
||||||
if (tc == PRI_TRANS_CAP_3_1K_AUDIO)
|
if (tc == PRI_TRANS_CAP_3_1K_AUDIO)
|
||||||
@ -1047,6 +1067,33 @@ static FUNC_RECV(receive_progress_indicator)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static FUNC_SEND(transmit_facility)
|
||||||
|
{
|
||||||
|
struct apdu_event *tmp;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (tmp = call->apdus; tmp; tmp = tmp->next) {
|
||||||
|
if (tmp->message == msgtype)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tmp) /* No APDU found */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (tmp->apdu_len > 235) { /* TODO: find out how much sapce we can use */
|
||||||
|
pri_message("Requested ADPU (%d bytes) is too long\n", tmp->apdu_len);
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(ie->data, tmp->apdu, tmp->apdu_len);
|
||||||
|
i += tmp->apdu_len;
|
||||||
|
|
||||||
|
return i + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
static FUNC_SEND(transmit_facility)
|
static FUNC_SEND(transmit_facility)
|
||||||
{
|
{
|
||||||
int i = 0, j, first_i, compsp = 0;
|
int i = 0, j, first_i, compsp = 0;
|
||||||
@ -1220,6 +1267,7 @@ static FUNC_SEND(transmit_facility)
|
|||||||
finish2:
|
finish2:
|
||||||
return (i ? i+2 : 0);
|
return (i ? i+2 : 0);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static FUNC_RECV(receive_facility)
|
static FUNC_RECV(receive_facility)
|
||||||
{
|
{
|
||||||
@ -1447,6 +1495,37 @@ static FUNC_DUMP(dump_time_date)
|
|||||||
pri_message(" ]\n");
|
pri_message(" ]\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static FUNC_DUMP(dump_keypad_facility)
|
||||||
|
{
|
||||||
|
char tmp[64] = "";
|
||||||
|
|
||||||
|
if (ie->len == 0 || ie->len > sizeof(tmp))
|
||||||
|
return;
|
||||||
|
|
||||||
|
strncpy(tmp, ie->data, sizeof(tmp));
|
||||||
|
pri_message("%c Keypad Facility (len=%2d) [ %s ]\n", prefix, ie->len, tmp );
|
||||||
|
}
|
||||||
|
|
||||||
|
static FUNC_RECV(receive_keypad_facility)
|
||||||
|
{
|
||||||
|
int mylen = 0;
|
||||||
|
|
||||||
|
if (ie->len == 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (ie->len > sizeof(call->digitbuf))
|
||||||
|
mylen = sizeof(call->digitbuf) - 1;
|
||||||
|
else
|
||||||
|
mylen = ie->len;
|
||||||
|
|
||||||
|
strncpy(call->digitbuf, ie->data, mylen);
|
||||||
|
|
||||||
|
/* I must be really neurotic */
|
||||||
|
call->digitbuf[sizeof(call->digitbuf)-1] = '\0';
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static FUNC_DUMP(dump_display)
|
static FUNC_DUMP(dump_display)
|
||||||
{
|
{
|
||||||
int x, y;
|
int x, y;
|
||||||
@ -2000,7 +2079,7 @@ struct ie ies[] = {
|
|||||||
{ 1, Q931_IE_NOTIFY_IND, "Notification Indicator", dump_notify, receive_notify, transmit_notify },
|
{ 1, Q931_IE_NOTIFY_IND, "Notification Indicator", dump_notify, receive_notify, transmit_notify },
|
||||||
{ 1, Q931_DISPLAY, "Display", dump_display, receive_display, transmit_display },
|
{ 1, Q931_DISPLAY, "Display", dump_display, receive_display, transmit_display },
|
||||||
{ 1, Q931_IE_TIME_DATE, "Date/Time", dump_time_date },
|
{ 1, Q931_IE_TIME_DATE, "Date/Time", dump_time_date },
|
||||||
{ 1, Q931_IE_KEYPAD_FACILITY, "Keypad Facility" },
|
{ 1, Q931_IE_KEYPAD_FACILITY, "Keypad Facility", dump_keypad_facility, receive_keypad_facility },
|
||||||
{ 0, Q931_IE_SIGNAL, "Signal", dump_signal },
|
{ 0, Q931_IE_SIGNAL, "Signal", dump_signal },
|
||||||
{ 1, Q931_IE_SWITCHHOOK, "Switch-hook" },
|
{ 1, Q931_IE_SWITCHHOOK, "Switch-hook" },
|
||||||
{ 1, Q931_IE_USER_USER, "User-User", dump_user_user, receive_user_user },
|
{ 1, Q931_IE_USER_USER, "User-User", dump_user_user, receive_user_user },
|
||||||
@ -2212,6 +2291,7 @@ static void q931_destroy(struct pri *pri, int cr, q931_call *c)
|
|||||||
pri_message("NEW_HANGUP DEBUG: Destroying the call, ourstate %s, peerstate %s\n",callstate2str(cur->ourcallstate),callstate2str(cur->peercallstate));
|
pri_message("NEW_HANGUP DEBUG: Destroying the call, ourstate %s, peerstate %s\n",callstate2str(cur->ourcallstate),callstate2str(cur->peercallstate));
|
||||||
if (cur->retranstimer)
|
if (cur->retranstimer)
|
||||||
pri_schedule_del(pri, cur->retranstimer);
|
pri_schedule_del(pri, cur->retranstimer);
|
||||||
|
pri_call_apdu_queue_cleanup(cur);
|
||||||
free(cur);
|
free(cur);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2410,6 +2490,8 @@ static int send_message(struct pri *pri, q931_call *c, int msgtype, int ies[])
|
|||||||
int offset=0;
|
int offset=0;
|
||||||
int x;
|
int x;
|
||||||
int codeset;
|
int codeset;
|
||||||
|
struct apdu_event *facevent = c->apdus;
|
||||||
|
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
len = sizeof(buf);
|
len = sizeof(buf);
|
||||||
init_header(pri, c, buf, &h, &mh, &len);
|
init_header(pri, c, buf, &h, &mh, &len);
|
||||||
@ -2417,11 +2499,30 @@ static int send_message(struct pri *pri, q931_call *c, int msgtype, int ies[])
|
|||||||
x=0;
|
x=0;
|
||||||
codeset = 0;
|
codeset = 0;
|
||||||
while(ies[x] > -1) {
|
while(ies[x] > -1) {
|
||||||
res = add_ie(pri, c, mh->msg, ies[x], (q931_ie *)(mh->data + offset), len, &codeset);
|
if (ies[x] == Q931_IE_FACILITY) {
|
||||||
|
res = 0;
|
||||||
|
while (facevent) {
|
||||||
|
if (!facevent->sent && (facevent->message == msgtype)) {
|
||||||
|
int tmpres;
|
||||||
|
tmpres = add_ie(pri, c, mh->msg, ies[x], (q931_ie *)(mh->data + offset), len, &codeset);
|
||||||
|
if (tmpres < 0) {
|
||||||
|
pri_error("!! Unable to add IE '%s'\n", ie2str(ies[x]));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
res += tmpres;
|
||||||
|
facevent->sent = 1;
|
||||||
|
}
|
||||||
|
facevent = facevent->next;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res = add_ie(pri, c, mh->msg, ies[x], (q931_ie *)(mh->data + offset), len, &codeset);
|
||||||
|
}
|
||||||
|
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
pri_error("!! Unable to add IE '%s'\n", ie2str(ies[x]));
|
pri_error("!! Unable to add IE '%s'\n", ie2str(ies[x]));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
offset += res;
|
offset += res;
|
||||||
len -= res;
|
len -= res;
|
||||||
x++;
|
x++;
|
||||||
@ -2479,6 +2580,13 @@ static int restart_ack(struct pri *pri, q931_call *c)
|
|||||||
return send_message(pri, c, Q931_RESTART_ACKNOWLEDGE, restart_ack_ies);
|
return send_message(pri, c, Q931_RESTART_ACKNOWLEDGE, restart_ack_ies);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int facility_ies[] = { Q931_IE_FACILITY, -1 };
|
||||||
|
|
||||||
|
int q931_facility(struct pri*pri, q931_call *c)
|
||||||
|
{
|
||||||
|
return send_message(pri, c, Q931_FACILITY, facility_ies);
|
||||||
|
}
|
||||||
|
|
||||||
static int notify_ies[] = { Q931_IE_NOTIFY_IND, -1 };
|
static int notify_ies[] = { Q931_IE_NOTIFY_IND, -1 };
|
||||||
|
|
||||||
int q931_notify(struct pri *pri, q931_call *c, int channel, int info)
|
int q931_notify(struct pri *pri, q931_call *c, int channel, int info)
|
||||||
@ -2737,6 +2845,8 @@ static int setup_ies[] = { Q931_BEARER_CAPABILITY, Q931_CHANNEL_IDENT, Q931_IE_F
|
|||||||
|
|
||||||
static int gr303_setup_ies[] = { Q931_BEARER_CAPABILITY, Q931_CHANNEL_IDENT, -1 };
|
static int gr303_setup_ies[] = { Q931_BEARER_CAPABILITY, Q931_CHANNEL_IDENT, -1 };
|
||||||
|
|
||||||
|
static int cis_setup_ies[] = { Q931_BEARER_CAPABILITY, Q931_CHANNEL_IDENT, Q931_IE_FACILITY, Q931_CALLED_PARTY_NUMBER, -1 };
|
||||||
|
|
||||||
int q931_setup(struct pri *pri, q931_call *c, struct pri_sr *req)
|
int q931_setup(struct pri *pri, q931_call *c, struct pri_sr *req)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
@ -2757,7 +2867,8 @@ int q931_setup(struct pri *pri, q931_call *c, struct pri_sr *req)
|
|||||||
c->channelno = req->channel;
|
c->channelno = req->channel;
|
||||||
c->slotmap = -1;
|
c->slotmap = -1;
|
||||||
c->nonisdn = req->nonisdn;
|
c->nonisdn = req->nonisdn;
|
||||||
c->newcall = 0;
|
c->newcall = 0;
|
||||||
|
c->justsignalling = req->justsignalling;
|
||||||
c->complete = req->numcomplete;
|
c->complete = req->numcomplete;
|
||||||
if (req->exclusive)
|
if (req->exclusive)
|
||||||
c->chanflags = FLAG_EXCLUSIVE;
|
c->chanflags = FLAG_EXCLUSIVE;
|
||||||
@ -2810,8 +2921,13 @@ int q931_setup(struct pri *pri, q931_call *c, struct pri_sr *req)
|
|||||||
c->progressmask = PRI_PROG_CALLER_NOT_ISDN;
|
c->progressmask = PRI_PROG_CALLER_NOT_ISDN;
|
||||||
else
|
else
|
||||||
c->progressmask = 0;
|
c->progressmask = 0;
|
||||||
|
|
||||||
|
pri_call_add_standard_apdus(pri, c);
|
||||||
|
|
||||||
if (pri->subchannel)
|
if (pri->subchannel)
|
||||||
res = send_message(pri, c, Q931_SETUP, gr303_setup_ies);
|
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
|
else
|
||||||
res = send_message(pri, c, Q931_SETUP, setup_ies);
|
res = send_message(pri, c, Q931_SETUP, setup_ies);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
@ -2961,6 +3077,8 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
|||||||
int missingmand;
|
int missingmand;
|
||||||
int codeset, cur_codeset;
|
int codeset, cur_codeset;
|
||||||
int last_ie[8];
|
int last_ie[8];
|
||||||
|
struct apdu_event *cur = NULL;
|
||||||
|
|
||||||
memset(last_ie, 0, sizeof(last_ie));
|
memset(last_ie, 0, sizeof(last_ie));
|
||||||
if (pri->debug & PRI_DEBUG_Q931_DUMP)
|
if (pri->debug & PRI_DEBUG_Q931_DUMP)
|
||||||
q931_dump(h, len, 0);
|
q931_dump(h, len, 0);
|
||||||
@ -3455,8 +3573,13 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
|||||||
q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
|
q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (c->ourcallstate!=Q931_CALL_STATE_OVERLAP_RECEIVING)
|
if (c->ourcallstate != Q931_CALL_STATE_OVERLAP_RECEIVING) {
|
||||||
break;
|
pri->ev.e = PRI_EVENT_KEYPAD_DIGIT;
|
||||||
|
pri->ev.digit.call = c;
|
||||||
|
pri->ev.digit.channel = c->channelno | (c->ds1no << 8);
|
||||||
|
strncpy(pri->ev.digit.digits, c->digitbuf, sizeof(pri->ev.digit.digits));
|
||||||
|
return Q931_RES_HAVEEVENT;
|
||||||
|
}
|
||||||
pri->ev.e = PRI_EVENT_INFO_RECEIVED;
|
pri->ev.e = PRI_EVENT_INFO_RECEIVED;
|
||||||
pri->ev.ring.call = c;
|
pri->ev.ring.call = c;
|
||||||
pri->ev.ring.channel = c->channelno | (c->ds1no << 8);
|
pri->ev.ring.channel = c->channelno | (c->ds1no << 8);
|
||||||
@ -3464,7 +3587,6 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
|||||||
strncpy(pri->ev.ring.callingsubaddr, c->callingsubaddr, sizeof(pri->ev.ring.callingsubaddr) - 1);
|
strncpy(pri->ev.ring.callingsubaddr, c->callingsubaddr, sizeof(pri->ev.ring.callingsubaddr) - 1);
|
||||||
pri->ev.ring.complete = c->complete; /* this covers IE 33 (Sending Complete) */
|
pri->ev.ring.complete = c->complete; /* this covers IE 33 (Sending Complete) */
|
||||||
return Q931_RES_HAVEEVENT;
|
return Q931_RES_HAVEEVENT;
|
||||||
break;
|
|
||||||
case Q931_STATUS_ENQUIRY:
|
case Q931_STATUS_ENQUIRY:
|
||||||
if (c->newcall) {
|
if (c->newcall) {
|
||||||
q931_release_complete(pri, c, PRI_CAUSE_INVALID_CALL_REFERENCE);
|
q931_release_complete(pri, c, PRI_CAUSE_INVALID_CALL_REFERENCE);
|
||||||
@ -3480,6 +3602,16 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
|||||||
c->peercallstate = Q931_CALL_STATE_OVERLAP_RECEIVING;
|
c->peercallstate = Q931_CALL_STATE_OVERLAP_RECEIVING;
|
||||||
pri->ev.e = PRI_EVENT_SETUP_ACK;
|
pri->ev.e = PRI_EVENT_SETUP_ACK;
|
||||||
pri->ev.setup_ack.channel = c->channelno;
|
pri->ev.setup_ack.channel = c->channelno;
|
||||||
|
|
||||||
|
cur = c->apdus;
|
||||||
|
while (cur) {
|
||||||
|
if (!cur->sent && cur->message == Q931_FACILITY) {
|
||||||
|
q931_facility(pri, c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
|
|
||||||
return Q931_RES_HAVEEVENT;
|
return Q931_RES_HAVEEVENT;
|
||||||
case Q931_NOTIFY:
|
case Q931_NOTIFY:
|
||||||
pri->ev.e = PRI_EVENT_NOTIFY;
|
pri->ev.e = PRI_EVENT_NOTIFY;
|
||||||
|
13
testprilib.c
13
testprilib.c
@ -53,6 +53,7 @@
|
|||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
#include "libpri.h"
|
#include "libpri.h"
|
||||||
|
#include "pri_q931.h"
|
||||||
|
|
||||||
#ifndef AF_LOCAL
|
#ifndef AF_LOCAL
|
||||||
#define AF_LOCAL AF_UNIX
|
#define AF_LOCAL AF_UNIX
|
||||||
@ -89,7 +90,7 @@ static void event1(struct pri *pri, pri_event *e)
|
|||||||
}
|
}
|
||||||
#if 0
|
#if 0
|
||||||
sr = pri_sr_new();
|
sr = pri_sr_new();
|
||||||
pri_sr_set_channel(sr, x, 0, 0);
|
pri_sr_set_channel(sr, x+1, 0, 0);
|
||||||
pri_sr_set_bearer(sr, 0, PRI_LAYER_1_ULAW);
|
pri_sr_set_bearer(sr, 0, PRI_LAYER_1_ULAW);
|
||||||
pri_sr_set_called(sr, dest, PRI_NATIONAL_ISDN, 1);
|
pri_sr_set_called(sr, dest, PRI_NATIONAL_ISDN, 1);
|
||||||
pri_sr_set_caller(sr, num, name, PRI_NATIONAL_ISDN, PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN);
|
pri_sr_set_caller(sr, num, name, PRI_NATIONAL_ISDN, PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN);
|
||||||
@ -107,6 +108,11 @@ static void event1(struct pri *pri, pri_event *e)
|
|||||||
}
|
}
|
||||||
printf("Setup %d calls!\n", TEST_CALLS);
|
printf("Setup %d calls!\n", TEST_CALLS);
|
||||||
break;
|
break;
|
||||||
|
case PRI_EVENT_RINGING:
|
||||||
|
printf("PRI 1: %s (%d)\n", pri_event2str(e->gen.e), e->gen.e);
|
||||||
|
q931_facility(pri, e->ringing.call);
|
||||||
|
pri_answer(pri, e->ringing.call, e->ringing.channel, 0);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
printf("PRI 1: %s (%d)\n", pri_event2str(e->gen.e), e->gen.e);
|
printf("PRI 1: %s (%d)\n", pri_event2str(e->gen.e), e->gen.e);
|
||||||
}
|
}
|
||||||
@ -116,6 +122,11 @@ static void event2(struct pri *pri, pri_event *e)
|
|||||||
{
|
{
|
||||||
/* CPE */
|
/* CPE */
|
||||||
switch(e->gen.e) {
|
switch(e->gen.e) {
|
||||||
|
case PRI_EVENT_RING:
|
||||||
|
printf("PRI 2: %s (%d)\n", pri_event2str(e->gen.e), e->gen.e);
|
||||||
|
pri_proceeding(pri, e->ring.call, e->ring.channel, 0);
|
||||||
|
pri_acknowledge(pri, e->ring.call, e->ring.channel, 0);
|
||||||
|
break;
|
||||||
case PRI_EVENT_DCHAN_UP:
|
case PRI_EVENT_DCHAN_UP:
|
||||||
default:
|
default:
|
||||||
printf("PRI 2: %s (%d)\n", pri_event2str(e->gen.e), e->gen.e);
|
printf("PRI 2: %s (%d)\n", pri_event2str(e->gen.e), e->gen.e);
|
||||||
|
Loading…
Reference in New Issue
Block a user