Major changes in preparation for GR-303 and NFAS support
git-svn-id: https://origsvn.digium.com/svn/libpri/trunk@101 2fbb986a-6c06-0410-b554-c9c1f0a7f128
This commit is contained in:
parent
bce8bfb87f
commit
f065327cc1
20
libpri.h
20
libpri.h
@ -49,6 +49,10 @@
|
||||
#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_NI1 7 /* National ISDN 1 */
|
||||
#define PRI_SWITCH_GR303_EOC 8 /* GR-303 Embedded Operations Channel */
|
||||
#define PRI_SWITCH_GR303_TMC 9 /* GR-303 Timeslot Management Channel */
|
||||
/* Switchtypes 10 - 20 are reserved for internal use */
|
||||
|
||||
|
||||
/* PRI D-Channel Events */
|
||||
#define PRI_EVENT_DCHAN_UP 1 /* D-channel is up */
|
||||
@ -338,14 +342,8 @@ extern int pri_need_more_info(struct pri *pri, q931_call *call, int channel, int
|
||||
Set non-isdn to non-zero if you are not connecting to ISDN equipment */
|
||||
extern int pri_answer(struct pri *pri, q931_call *call, int channel, int nonisdn);
|
||||
|
||||
#if 0
|
||||
/* deprecated routines, use pri_hangup */
|
||||
/* Release/Reject a call */
|
||||
extern int pri_release(struct pri *pri, q931_call *call, int cause);
|
||||
/* Set CRV reference for GR-303 calls */
|
||||
|
||||
/* Hangup / Disconnect a call */
|
||||
extern int pri_disconnect(struct pri *pri, q931_call *call, int cause);
|
||||
#endif
|
||||
|
||||
#undef pri_release
|
||||
#undef pri_disconnect
|
||||
@ -369,6 +367,12 @@ extern int pri_reset(struct pri *pri, int channel);
|
||||
/* Create a new call */
|
||||
extern q931_call *pri_new_call(struct pri *pri);
|
||||
|
||||
/* Retrieve CRV reference for GR-303 calls. Returns >0 on success. */
|
||||
extern int pri_get_crv(struct pri *pri, q931_call *call, int *callmode);
|
||||
|
||||
/* Retrieve CRV reference for GR-303 calls. CRV must be >0, call mode should be 0 */
|
||||
extern int pri_set_crv(struct pri *pri, q931_call *call, int crv, int callmode);
|
||||
|
||||
/* How long until you need to poll for a new event */
|
||||
extern struct timeval *pri_schedule_next(struct pri *pri);
|
||||
|
||||
@ -400,4 +404,6 @@ extern int pri_progress(struct pri *pri, q931_call *c, int channel, int info);
|
||||
#define PRI_PROCEEDING_FULL
|
||||
/* Send call proceeding */
|
||||
extern int pri_proceeding(struct pri *pri, q931_call *c, int channel, int info);
|
||||
|
||||
#define PRI_GR303_SUPPORT
|
||||
#endif
|
||||
|
56
pri.c
56
pri.c
@ -53,12 +53,16 @@ char *pri_switch2str(int sw)
|
||||
return "National ISDN 1";
|
||||
case PRI_SWITCH_EUROISDN_E1:
|
||||
return "EuroISDN";
|
||||
case PRI_SWITCH_GR303_EOC:
|
||||
return "GR303 EOC";
|
||||
case PRI_SWITCH_GR303_TMC:
|
||||
return "GR303 TMC";
|
||||
default:
|
||||
return "Unknown switchtype";
|
||||
}
|
||||
}
|
||||
|
||||
struct pri *pri_new(int fd, int node, int switchtype)
|
||||
static struct pri *__pri_new(int fd, int node, int switchtype, struct pri *master)
|
||||
{
|
||||
struct pri *p;
|
||||
p = malloc(sizeof(struct pri));
|
||||
@ -68,18 +72,55 @@ struct pri *pri_new(int fd, int node, int switchtype)
|
||||
p->localtype = node;
|
||||
p->switchtype = switchtype;
|
||||
p->cref = 1;
|
||||
p->sapi = Q921_SAPI_CALL_CTRL;
|
||||
p->tei = 0;
|
||||
p->protodisc = Q931_PROTOCOL_DISCRIMINATOR;
|
||||
p->master = master;
|
||||
#ifdef LIBPRI_COUNTERS
|
||||
p->q921_rxcount = 0;
|
||||
p->q921_txcount = 0;
|
||||
p->q931_rxcount = 0;
|
||||
p->q931_txcount = 0;
|
||||
#endif
|
||||
if (switchtype == PRI_SWITCH_GR303_EOC) {
|
||||
p->protodisc = GR303_PROTOCOL_DISCRIMINATOR;
|
||||
p->sapi = Q921_SAPI_GR303_EOC;
|
||||
p->tei = Q921_TEI_GR303_EOC_OPS;
|
||||
p->subchannel = __pri_new(-1, node, PRI_SWITCH_GR303_EOC_PATH, p);
|
||||
if (!p->subchannel) {
|
||||
free(p);
|
||||
p = NULL;
|
||||
}
|
||||
} else if (switchtype == PRI_SWITCH_GR303_TMC) {
|
||||
p->protodisc = GR303_PROTOCOL_DISCRIMINATOR;
|
||||
p->sapi = Q921_SAPI_GR303_TMC_CALLPROC;
|
||||
p->tei = Q921_TEI_GR303_TMC_CALLPROC;
|
||||
p->subchannel = __pri_new(-1, node, PRI_SWITCH_GR303_TMC_SWITCHING, p);
|
||||
if (!p->subchannel) {
|
||||
free(p);
|
||||
p = NULL;
|
||||
}
|
||||
} else if (switchtype == PRI_SWITCH_GR303_TMC_SWITCHING) {
|
||||
p->protodisc = GR303_PROTOCOL_DISCRIMINATOR;
|
||||
p->sapi = Q921_SAPI_GR303_TMC_SWITCHING;
|
||||
p->tei = Q921_TEI_GR303_TMC_SWITCHING;
|
||||
} else if (switchtype == PRI_SWITCH_GR303_EOC_PATH) {
|
||||
p->protodisc = GR303_PROTOCOL_DISCRIMINATOR;
|
||||
p->sapi = Q921_SAPI_GR303_EOC;
|
||||
p->tei = Q921_TEI_GR303_EOC_PATH;
|
||||
}
|
||||
/* Start Q.921 layer, Wait if we're the network */
|
||||
q921_start(p, p->localtype == PRI_CPE);
|
||||
if (p)
|
||||
q921_start(p, p->localtype == PRI_CPE);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
struct pri *pri_new(int fd, int node, int switchtype)
|
||||
{
|
||||
return __pri_new(fd, node, switchtype, NULL);
|
||||
}
|
||||
|
||||
char *pri_event2str(int id)
|
||||
{
|
||||
switch(id) {
|
||||
@ -182,6 +223,8 @@ void pri_set_debug(struct pri *pri, int debug)
|
||||
if (!pri)
|
||||
return;
|
||||
pri->debug = debug;
|
||||
if (pri->subchannel)
|
||||
pri_set_debug(pri->subchannel, debug);
|
||||
}
|
||||
|
||||
int pri_acknowledge(struct pri *pri, q931_call *call, int channel, int info)
|
||||
@ -392,3 +435,12 @@ void pri_dump_info(struct pri *pri)
|
||||
pri_message("Overlap Dial: %d\n", pri->overlapdial);
|
||||
}
|
||||
|
||||
int pri_get_crv(struct pri *pri, q931_call *call, int *callmode)
|
||||
{
|
||||
return q931_call_getcrv(pri, call, callmode);
|
||||
}
|
||||
|
||||
int pri_set_crv(struct pri *pri, q931_call *call, int crv, int callmode)
|
||||
{
|
||||
return q931_call_setcrv(pri, call, crv, callmode);
|
||||
}
|
||||
|
@ -42,12 +42,18 @@ enum q931_mode;
|
||||
|
||||
struct pri {
|
||||
int fd; /* File descriptor for D-Channel */
|
||||
struct pri *subchannel; /* Sub-channel if appropriate */
|
||||
struct pri *master; /* Master channel if appropriate */
|
||||
struct pri_sched pri_sched[MAX_SCHED]; /* Scheduled events */
|
||||
int debug; /* Debug stuff */
|
||||
int state; /* State of D-channel */
|
||||
int switchtype; /* Switch type */
|
||||
int localtype; /* Local network type (unknown, network, cpe) */
|
||||
int remotetype; /* Remote network type (unknown, network, cpe) */
|
||||
|
||||
int sapi;
|
||||
int tei;
|
||||
int protodisc;
|
||||
|
||||
/* Q.921 State */
|
||||
int q921_state;
|
||||
@ -93,6 +99,10 @@ struct pri {
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Internal switch types */
|
||||
#define PRI_SWITCH_GR303_EOC_PATH 10
|
||||
#define PRI_SWITCH_GR303_TMC_SWITCHING 11
|
||||
|
||||
extern int pri_schedule_event(struct pri *pri, int ms, void (*function)(void *data), void *data);
|
||||
|
||||
extern pri_event *pri_schedule_run(struct pri *pri);
|
||||
|
11
pri_q921.h
11
pri_q921.h
@ -47,8 +47,17 @@
|
||||
#define Q921_FRAMETYPE_S 0x1
|
||||
|
||||
#define Q921_TEI_GROUP 127
|
||||
#define Q921_TEI_GR303_EOC_PATH 0
|
||||
#define Q921_TEI_GR303_EOC_OPS 4
|
||||
#define Q921_TEI_GR303_TMC_SWITCHING 0
|
||||
#define Q921_TEI_GR303_TMC_CALLPROC 0
|
||||
|
||||
#define Q921_SAPI_CALL_CTRL 0
|
||||
#define Q921_SAPI_GR303_EOC 1
|
||||
#define Q921_SAPI_GR303_TMC_SWITCHING 1
|
||||
#define Q921_SAPI_GR303_TMC_CALLPROC 0
|
||||
|
||||
|
||||
#define Q921_SAPI_CALL_CTRL 0
|
||||
#define Q921_SAPI_PACKET_MODE 1
|
||||
#define Q921_SAPI_X25_LAYER3 16
|
||||
#define Q921_SAPI_LAYER2_MANAGEMENT 63
|
||||
|
@ -113,6 +113,7 @@ typedef struct q931_ie {
|
||||
#define Q931_RES_INERRROR (1 << 1)
|
||||
|
||||
#define Q931_PROTOCOL_DISCRIMINATOR 0x08
|
||||
#define GR303_PROTOCOL_DISCRIMINATOR 0x4f
|
||||
|
||||
/* Q.931 / National ISDN Message Types */
|
||||
|
||||
@ -261,6 +262,10 @@ extern int q931_hangup(struct pri *pri, q931_call *call, int cause);
|
||||
|
||||
extern int q931_restart(struct pri *pri, int channel);
|
||||
|
||||
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 q931_call *q931_new_call(struct pri *pri);
|
||||
|
||||
extern int q931_setup(struct pri *pri, q931_call *c, int transmode, int channel, int exclusive,
|
||||
|
31
prisched.c
31
prisched.c
@ -60,6 +60,9 @@ struct timeval *pri_schedule_next(struct pri *pri)
|
||||
{
|
||||
struct timeval *closest = NULL;
|
||||
int x;
|
||||
/* Check subchannels */
|
||||
if (pri->subchannel)
|
||||
closest = pri_schedule_next(pri->subchannel);
|
||||
for (x=1;x<MAX_SCHED;x++) {
|
||||
if (pri->pri_sched[x].callback &&
|
||||
(!closest || (closest->tv_sec > pri->pri_sched[x].when.tv_sec) ||
|
||||
@ -70,19 +73,23 @@ struct timeval *pri_schedule_next(struct pri *pri)
|
||||
return closest;
|
||||
}
|
||||
|
||||
pri_event *pri_schedule_run(struct pri *pri)
|
||||
static pri_event *__pri_schedule_run(struct pri *pri, struct timeval *tv)
|
||||
{
|
||||
struct timeval tv;
|
||||
int x;
|
||||
void (*callback)(void *);
|
||||
void *data;
|
||||
gettimeofday(&tv, NULL);
|
||||
pri_event *e;
|
||||
if (pri->subchannel) {
|
||||
if ((e = __pri_schedule_run(pri->subchannel, tv))) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
for (x=1;x<MAX_SCHED;x++) {
|
||||
if (pri->pri_sched[x].callback &&
|
||||
((pri->pri_sched[x].when.tv_sec < tv.tv_sec) ||
|
||||
((pri->pri_sched[x].when.tv_sec == tv.tv_sec) &&
|
||||
(pri->pri_sched[x].when.tv_usec <= tv.tv_usec)))) {
|
||||
pri->schedev = 0;
|
||||
((pri->pri_sched[x].when.tv_sec < tv->tv_sec) ||
|
||||
((pri->pri_sched[x].when.tv_sec == tv->tv_sec) &&
|
||||
(pri->pri_sched[x].when.tv_usec <= tv->tv_usec)))) {
|
||||
pri->schedev = 0;
|
||||
callback = pri->pri_sched[x].callback;
|
||||
data = pri->pri_sched[x].data;
|
||||
pri->pri_sched[x].callback = NULL;
|
||||
@ -90,11 +97,19 @@ pri_event *pri_schedule_run(struct pri *pri)
|
||||
callback(data);
|
||||
if (pri->schedev)
|
||||
return &pri->ev;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pri_event *pri_schedule_run(struct pri *pri)
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return __pri_schedule_run(pri, &tv);
|
||||
}
|
||||
|
||||
|
||||
void pri_schedule_del(struct pri *pri,int id)
|
||||
{
|
||||
if ((id >= MAX_SCHED) || (id < 0))
|
||||
|
@ -120,6 +120,10 @@ static int str2switch(char *swtype)
|
||||
return PRI_SWITCH_ATT4ESS;
|
||||
if (!strcasecmp(swtype, "euroisdn"))
|
||||
return PRI_SWITCH_EUROISDN_E1;
|
||||
if (!strcasecmp(swtype, "gr303eoc"))
|
||||
return PRI_SWITCH_GR303_EOC;
|
||||
if (!strcasecmp(swtype, "gr303tmc"))
|
||||
return PRI_SWITCH_GR303_TMC;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -299,6 +303,7 @@ static int run_pri(int dfd, int swtype, int node)
|
||||
fprintf(stderr, "Unable to create PRI\n");
|
||||
return -1;
|
||||
}
|
||||
pri_set_debug(pri, -1);
|
||||
for (;;) {
|
||||
|
||||
/* Run the D-Channel */
|
||||
|
68
q921.c
68
q921.c
@ -41,12 +41,12 @@
|
||||
#define RANDOM_DROPS
|
||||
*/
|
||||
|
||||
#define Q921_INIT(hf) do { \
|
||||
#define Q921_INIT(pri, hf) do { \
|
||||
memset(&(hf),0,sizeof(hf)); \
|
||||
(hf).h.sapi = 0; \
|
||||
(hf).h.sapi = (pri)->sapi; \
|
||||
(hf).h.ea1 = 0; \
|
||||
(hf).h.ea2 = 1; \
|
||||
(hf).h.tei = 0; \
|
||||
(hf).h.tei = (pri)->tei; \
|
||||
} while(0)
|
||||
|
||||
static void reschedule_t203(struct pri *pri);
|
||||
@ -67,6 +67,8 @@ static void q921_discard_retransmissions(struct pri *pri)
|
||||
static int q921_transmit(struct pri *pri, q921_h *h, int len)
|
||||
{
|
||||
int res;
|
||||
if (pri->master)
|
||||
return q921_transmit(pri->master, h, len);
|
||||
#ifdef RANDOM_DROPS
|
||||
if (!(random() % 3)) {
|
||||
pri_message(" === Dropping Packet ===\n");
|
||||
@ -92,7 +94,7 @@ static int q921_transmit(struct pri *pri, q921_h *h, int len)
|
||||
static void q921_send_ua(struct pri *pri, int pfbit)
|
||||
{
|
||||
q921_h h;
|
||||
Q921_INIT(h);
|
||||
Q921_INIT(pri, h);
|
||||
h.u.m3 = 3; /* M3 = 3 */
|
||||
h.u.m2 = 0; /* M2 = 0 */
|
||||
h.u.p_f = pfbit; /* Final bit on */
|
||||
@ -124,7 +126,7 @@ static void q921_send_sabme(void *vpri, int now)
|
||||
pri->sabme_timer = pri_schedule_event(pri, T_200, q921_send_sabme_now, pri);
|
||||
if (!now)
|
||||
return;
|
||||
Q921_INIT(h);
|
||||
Q921_INIT(pri, h);
|
||||
h.u.m3 = 3; /* M3 = 3 */
|
||||
h.u.m2 = 3; /* M2 = 3 */
|
||||
h.u.p_f = 1; /* Poll bit set */
|
||||
@ -261,7 +263,7 @@ static pri_event *q921_ack_rx(struct pri *pri, int ack)
|
||||
static void q921_reject(struct pri *pri, int pf)
|
||||
{
|
||||
q921_h h;
|
||||
Q921_INIT(h);
|
||||
Q921_INIT(pri, h);
|
||||
h.s.x0 = 0; /* Always 0 */
|
||||
h.s.ss = 2; /* Reject */
|
||||
h.s.ft = 1; /* Frametype (01) */
|
||||
@ -286,7 +288,7 @@ static void q921_reject(struct pri *pri, int pf)
|
||||
|
||||
static void q921_rr(struct pri *pri, int pbit, int cmd) {
|
||||
q921_h h;
|
||||
Q921_INIT(h);
|
||||
Q921_INIT(pri, h);
|
||||
h.s.x0 = 0; /* Always 0 */
|
||||
h.s.ss = 0; /* Receive Ready */
|
||||
h.s.ft = 1; /* Frametype (01) */
|
||||
@ -366,7 +368,7 @@ int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr)
|
||||
f = malloc(sizeof(q921_frame) + len + 2);
|
||||
memset(f,0,sizeof(q921_frame) + len + 2);
|
||||
if (f) {
|
||||
Q921_INIT(f->h);
|
||||
Q921_INIT(pri, f->h);
|
||||
switch(pri->localtype) {
|
||||
case PRI_NETWORK:
|
||||
if (cr)
|
||||
@ -678,28 +680,11 @@ void q921_reset(struct pri *pri)
|
||||
q921_discard_retransmissions(pri);
|
||||
}
|
||||
|
||||
static pri_event *__q921_receive(struct pri *pri, q921_h *h, int len)
|
||||
static pri_event *__q921_receive_qualified(struct pri *pri, q921_h *h, int len)
|
||||
{
|
||||
q921_frame *f;
|
||||
pri_event *ev;
|
||||
int sendnow;
|
||||
/* Discard FCS */
|
||||
len -= 2;
|
||||
|
||||
if (pri->debug & PRI_DEBUG_Q921_DUMP)
|
||||
q921_dump(h, len, pri->debug & PRI_DEBUG_Q921_RAW, 0);
|
||||
|
||||
/* Check some reject conditions -- Start by rejecting improper ea's */
|
||||
if (h->h.ea1 || !(h->h.ea2))
|
||||
return NULL;
|
||||
|
||||
/* Check for broadcasts - not yet handled */
|
||||
if (h->h.tei == Q921_TEI_GROUP)
|
||||
return NULL;
|
||||
|
||||
/* Check for SAPIs we don't yet handle */
|
||||
if (h->h.sapi != Q921_SAPI_CALL_CTRL)
|
||||
return NULL;
|
||||
|
||||
switch(h->h.data[0] & Q921_FRAMETYPE_MASK) {
|
||||
case 0:
|
||||
@ -891,11 +876,40 @@ static pri_event *__q921_receive(struct pri *pri, q921_h *h, int len)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static pri_event *__q921_receive(struct pri *pri, q921_h *h, int len)
|
||||
{
|
||||
pri_event *ev;
|
||||
/* Discard FCS */
|
||||
len -= 2;
|
||||
|
||||
if (!pri->master && pri->debug & PRI_DEBUG_Q921_DUMP)
|
||||
q921_dump(h, len, pri->debug & PRI_DEBUG_Q921_RAW, 0);
|
||||
|
||||
/* Check some reject conditions -- Start by rejecting improper ea's */
|
||||
if (h->h.ea1 || !(h->h.ea2))
|
||||
return NULL;
|
||||
|
||||
/* Check for broadcasts - not yet handled */
|
||||
if (h->h.tei == Q921_TEI_GROUP)
|
||||
return NULL;
|
||||
|
||||
/* Check for SAPIs we don't yet handle */
|
||||
if ((h->h.sapi != pri->sapi) || (h->h.tei != pri->tei)) {
|
||||
/* If it's not us, try any subchannels we have */
|
||||
if (pri->subchannel)
|
||||
return q921_receive(pri->subchannel, h, len + 2);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
ev = __q921_receive_qualified(pri, h, len);
|
||||
reschedule_t203(pri);
|
||||
return ev;
|
||||
}
|
||||
|
||||
pri_event *q921_receive(struct pri *pri, q921_h *h, int len)
|
||||
{
|
||||
pri_event *e;
|
||||
e = __q921_receive(pri, h, len);
|
||||
reschedule_t203(pri);
|
||||
#ifdef LIBPRI_COUNTERS
|
||||
pri->q921_rxcount++;
|
||||
#endif
|
||||
|
114
q931.c
114
q931.c
@ -281,7 +281,7 @@ static void call_init(struct q931_call *c)
|
||||
c->cr = -1;
|
||||
c->slotmap = -1;
|
||||
c->channelno = -1;
|
||||
c->ds1no = -1;
|
||||
c->ds1no = 0;
|
||||
c->chanflags = 0;
|
||||
c->next = NULL;
|
||||
c->sentchannel = 0;
|
||||
@ -361,7 +361,10 @@ static int transmit_channel_id(struct pri *pri, q931_call *call, int msgtype, q9
|
||||
{
|
||||
int pos=0;
|
||||
/* Start with standard stuff */
|
||||
ie->data[pos] = 0xa1;
|
||||
if (pri->switchtype == PRI_SWITCH_GR303_TMC)
|
||||
ie->data[pos] = 0x61;
|
||||
else
|
||||
ie->data[pos] = 0xa1;
|
||||
/* Add exclusive flag if necessary */
|
||||
if (call->chanflags & FLAG_EXCLUSIVE)
|
||||
ie->data[pos] |= 0x08;
|
||||
@ -370,7 +373,7 @@ static int transmit_channel_id(struct pri *pri, q931_call *call, int msgtype, q9
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (call->ds1no > -1) {
|
||||
if (call->ds1no > 0) {
|
||||
/* Note that we are specifying the identifier */
|
||||
ie->data[pos++] |= 0x40;
|
||||
/* We need to use the Channel Identifier Present thingy. Just specify it and we're done */
|
||||
@ -394,7 +397,7 @@ static int transmit_channel_id(struct pri *pri, q931_call *call, int msgtype, q9
|
||||
return pos + 2;
|
||||
}
|
||||
}
|
||||
if (call->ds1no > -1) {
|
||||
if (call->ds1no > 0) {
|
||||
/* We're done */
|
||||
return pos + 2;
|
||||
}
|
||||
@ -424,7 +427,6 @@ static void dump_channel_id(q931_ie *ie, int len, char prefix)
|
||||
/* Explicitly defined DS1 */
|
||||
pri_message("%c Ext: %d DS1 Identifier: %d \n", prefix, (ie->data[pos] & 0x80) >> 7, ie->data[pos] & 0x7f);
|
||||
pos++;
|
||||
len--;
|
||||
} else {
|
||||
/* Implicitly defined DS1 */
|
||||
}
|
||||
@ -963,7 +965,8 @@ static int receive_facility(struct pri *pri, q931_call *call, int msgtype, q931_
|
||||
|
||||
static int transmit_progress_indicator(struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len)
|
||||
{
|
||||
if (call->progress > 0) {
|
||||
/* Can't send progress indicator on GR-303 -- EVER! */
|
||||
if (!pri->subchannel && (call->progress > 0)) {
|
||||
ie->data[0] = 0x80 | (call->progcode << 5) | (call->progloc);
|
||||
ie->data[1] = 0x80 | (call->progress);
|
||||
return 4;
|
||||
@ -1405,6 +1408,7 @@ static char *disc2str(int disc)
|
||||
{
|
||||
static struct msgtype discs[] = {
|
||||
{ Q931_PROTOCOL_DISCRIMINATOR, "Q.931" },
|
||||
{ GR303_PROTOCOL_DISCRIMINATOR, "GR-303" },
|
||||
{ 0x3, "AT&T Maintenance" },
|
||||
};
|
||||
return code2str(disc, discs, sizeof(discs) / sizeof(discs[0]));
|
||||
@ -1452,12 +1456,12 @@ static int q931_handle_ie(struct pri *pri, q931_call *c, int msg, q931_ie *ie)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void init_header(q931_call *call, char *buf, q931_h **hb, q931_mh **mhb, int *len)
|
||||
static void init_header(struct pri *pri, q931_call *call, char *buf, q931_h **hb, q931_mh **mhb, int *len)
|
||||
{
|
||||
/* Returns header and message header and modifies length in place */
|
||||
q931_h *h = (q931_h *)buf;
|
||||
q931_mh * mh = (q931_mh *)(h->contents + 2);
|
||||
h->pd = Q931_PROTOCOL_DISCRIMINATOR;
|
||||
h->pd = pri->protodisc;
|
||||
h->x0 = 0; /* Reserved 0 */
|
||||
h->crlen = 2; /* Two bytes of Call Reference. Invert the top bit to make it from our sense */
|
||||
if (call->cr || call->forceinvert) {
|
||||
@ -1468,6 +1472,10 @@ static void init_header(q931_call *call, char *buf, q931_h **hb, q931_mh **mhb,
|
||||
h->crv[0] = 0;
|
||||
h->crv[1] = 0;
|
||||
}
|
||||
if (pri->subchannel) {
|
||||
/* On GR-303, top bit is always 0 */
|
||||
h->crv[0] &= 0x7f;
|
||||
}
|
||||
mh->f = 0;
|
||||
*hb = h;
|
||||
*mhb = mh;
|
||||
@ -1500,7 +1508,7 @@ static int send_message(struct pri *pri, q931_call *c, int msgtype, int ies[])
|
||||
int x;
|
||||
memset(buf, 0, sizeof(buf));
|
||||
len = sizeof(buf);
|
||||
init_header(c, buf, &h, &mh, &len);
|
||||
init_header(pri, c, buf, &h, &mh, &len);
|
||||
mh->msg = msgtype;
|
||||
x=0;
|
||||
while(ies[x] > -1) {
|
||||
@ -1597,8 +1605,11 @@ static int call_proceeding_ies[] = { Q931_CHANNEL_IDENT, Q931_PROGRESS_INDICATOR
|
||||
|
||||
int q931_call_proceeding(struct pri *pri, q931_call *c, int channel, int info)
|
||||
{
|
||||
if (channel)
|
||||
if (channel) {
|
||||
c->ds1no = (channel & 0xff00) >> 8;
|
||||
channel &= 0xff;
|
||||
c->channelno = channel;
|
||||
}
|
||||
c->chanflags &= ~FLAG_PREFERRED;
|
||||
c->chanflags |= FLAG_EXCLUSIVE;
|
||||
c->ourcallstate = Q931_CALL_STATE_INCOMING_CALL_PROCEEDING;
|
||||
@ -1639,8 +1650,11 @@ static int connect_ies[] = { Q931_CHANNEL_IDENT, Q931_PROGRESS_INDICATOR, -1 };
|
||||
|
||||
int q931_setup_ack(struct pri *pri, q931_call *c, int channel, int nonisdn)
|
||||
{
|
||||
if (channel)
|
||||
c->channelno = channel;
|
||||
if (channel) {
|
||||
c->ds1no = (channel & 0xff00) >> 8;
|
||||
channel &= 0xff;
|
||||
c->channelno = channel;
|
||||
}
|
||||
c->chanflags &= ~FLAG_PREFERRED;
|
||||
c->chanflags |= FLAG_EXCLUSIVE;
|
||||
if (nonisdn && (pri->switchtype != PRI_SWITCH_DMS100)) {
|
||||
@ -1707,8 +1721,11 @@ static void pri_disconnect_timeout(void *data)
|
||||
|
||||
int q931_connect(struct pri *pri, q931_call *c, int channel, int nonisdn)
|
||||
{
|
||||
if (channel)
|
||||
c->channelno = channel;
|
||||
if (channel) {
|
||||
c->ds1no = (channel & 0xff00) >> 8;
|
||||
channel &= 0xff;
|
||||
c->channelno = channel;
|
||||
}
|
||||
c->chanflags &= ~FLAG_PREFERRED;
|
||||
c->chanflags |= FLAG_EXCLUSIVE;
|
||||
if (nonisdn && (pri->switchtype != PRI_SWITCH_DMS100)) {
|
||||
@ -1765,7 +1782,9 @@ int q931_restart(struct pri *pri, int channel)
|
||||
if (!channel)
|
||||
return -1;
|
||||
c->ri = 0;
|
||||
c->channelno = channel;
|
||||
c->ds1no = (channel & 0xff00) >> 8;
|
||||
channel &= 0xff;
|
||||
c->channelno = channel;
|
||||
c->chanflags &= ~FLAG_PREFERRED;
|
||||
c->chanflags |= FLAG_EXCLUSIVE;
|
||||
c->ourcallstate = Q931_CALL_STATE_RESTART;
|
||||
@ -1810,9 +1829,12 @@ int q931_setup(struct pri *pri, q931_call *c, int transmode, int channel, int ex
|
||||
if (!userl1)
|
||||
userl1 = PRI_LAYER_1_ULAW;
|
||||
c->userl1 = userl1;
|
||||
c->channelno = channel;
|
||||
c->ds1no = (channel & 0xff00) >> 8;
|
||||
channel &= 0xff;
|
||||
c->channelno = channel;
|
||||
c->slotmap = -1;
|
||||
c->ds1no = -1;
|
||||
c->ds1no = (channel & 0xff00) >> 8;
|
||||
channel &= 0xff;
|
||||
c->nonisdn = nonisdn;
|
||||
c->newcall = 0;
|
||||
if (exclusive)
|
||||
@ -1998,8 +2020,8 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
||||
h->raw[h->crlen + 2] -= 0x8;
|
||||
q931_xmit(pri, h, len, 1);
|
||||
return 0;
|
||||
} else if (h->pd != Q931_PROTOCOL_DISCRIMINATOR) {
|
||||
pri_error("Warning: unknown protocol discriminator received\n");
|
||||
} else if (h->pd != pri->protodisc) {
|
||||
pri_error("Warning: unknown/inappropriate protocol discriminator received (%02x/%d)\n", h->pd, h->pd);
|
||||
return 0;
|
||||
}
|
||||
c = q931_getcall(pri, q931_cr(h));
|
||||
@ -2016,7 +2038,7 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
||||
c->channelno = -1;
|
||||
c->slotmap = -1;
|
||||
c->chanflags = 0;
|
||||
c->ds1no = -1;
|
||||
c->ds1no = 0;
|
||||
c->ri = -1;
|
||||
break;
|
||||
case Q931_FACILITY:
|
||||
@ -2028,7 +2050,7 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
||||
c->channelno = -1;
|
||||
c->slotmap = -1;
|
||||
c->chanflags = 0;
|
||||
c->ds1no = -1;
|
||||
c->ds1no = 0;
|
||||
c->ri = -1;
|
||||
c->transcapability = -1;
|
||||
c->transmoderate = -1;
|
||||
@ -2148,16 +2170,10 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
||||
missingmand = 0;
|
||||
for (x=0;x<MAX_MAND_IES;x++) {
|
||||
if (mandies[x]) {
|
||||
pri_error("XXX Missing mandatory IE %d/%s XXX\n", mandies[x], ie2str(mandies[x]));
|
||||
missingmand++;
|
||||
}
|
||||
}
|
||||
/* check if there is no channel identyfication when we're configured as network -> that's not an error */
|
||||
if (missingmand && pri->localtype == PRI_NETWORK && mh->msg == Q931_SETUP) {
|
||||
for (x=0;x<MAX_MAND_IES;x++) {
|
||||
if (mandies[x] == Q931_CHANNEL_IDENT) {
|
||||
missingmand--;
|
||||
break;
|
||||
/* check if there is no channel identification when we're configured as network -> that's not an error */
|
||||
if ((pri->localtype != PRI_NETWORK) || (mh->msg != Q931_SETUP) || (mandies[x] != Q931_CHANNEL_IDENT)) {
|
||||
pri_error("XXX Missing mandatory IE %d/%s XXX\n", mandies[x], ie2str(mandies[x]));
|
||||
missingmand++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2193,7 +2209,7 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
||||
/* it's not yet a call since higher level can respond with RELEASE or RELEASE_COMPLETE */
|
||||
c->alive = 0;
|
||||
pri->ev.e = PRI_EVENT_RING;
|
||||
pri->ev.ring.channel = c->channelno;
|
||||
pri->ev.ring.channel = c->channelno | (c->ds1no << 8);
|
||||
pri->ev.ring.callingpres = c->callerpres;
|
||||
pri->ev.ring.callingplan = c->callerplan;
|
||||
strncpy(pri->ev.ring.callingnum, c->callernum, sizeof(pri->ev.ring.callingnum) - 1);
|
||||
@ -2221,7 +2237,7 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
||||
c->ourcallstate = Q931_CALL_STATE_CALL_DELIVERED;
|
||||
c->peercallstate = Q931_CALL_STATE_CALL_RECEIVED;
|
||||
pri->ev.e = PRI_EVENT_RINGING;
|
||||
pri->ev.ringing.channel = c->channelno;
|
||||
pri->ev.ringing.channel = c->channelno | (c->ds1no << 8);
|
||||
pri->ev.ringing.cref = c->cr;
|
||||
pri->ev.ringing.call = c;
|
||||
return Q931_RES_HAVEEVENT;
|
||||
@ -2237,7 +2253,7 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
||||
c->ourcallstate = Q931_CALL_STATE_ACTIVE;
|
||||
c->peercallstate = Q931_CALL_STATE_CONNECT_REQUEST;
|
||||
pri->ev.e = PRI_EVENT_ANSWER;
|
||||
pri->ev.answer.channel = c->channelno;
|
||||
pri->ev.answer.channel = c->channelno | (c->ds1no << 8);
|
||||
pri->ev.answer.cref = c->cr;
|
||||
pri->ev.answer.call = c;
|
||||
q931_connect_acknowledge(pri, c);
|
||||
@ -2250,7 +2266,7 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
||||
pri->ev.e = PRI_EVENT_FACNAME;
|
||||
strncpy(pri->ev.facname.callingname, c->callername, sizeof(pri->ev.facname.callingname) - 1);
|
||||
strncpy(pri->ev.facname.callingnum, c->callernum, sizeof(pri->ev.facname.callingname) - 1);
|
||||
pri->ev.facname.channel = c->channelno;
|
||||
pri->ev.facname.channel = c->channelno | (c->ds1no << 8);
|
||||
pri->ev.facname.cref = c->cr;
|
||||
pri->ev.facname.call = c;
|
||||
#if 0
|
||||
@ -2277,7 +2293,7 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
||||
break;
|
||||
}
|
||||
pri->ev.e = PRI_EVENT_PROCEEDING;
|
||||
pri->ev.proceeding.channel = c->channelno;
|
||||
pri->ev.proceeding.channel = c->channelno | (c->ds1no << 8);
|
||||
if (mh->msg == Q931_CALL_PROCEEDING) {
|
||||
c->ourcallstate = Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING;
|
||||
c->peercallstate = Q931_CALL_STATE_INCOMING_CALL_PROCEEDING;
|
||||
@ -2312,7 +2328,7 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
||||
(c->cause != PRI_CAUSE_INTERWORKING))
|
||||
pri_error("Received unsolicited status: %s\n", pri_cause2str(c->cause));
|
||||
if (!c->sugcallstate) {
|
||||
pri->ev.hangup.channel = c->channelno;
|
||||
pri->ev.hangup.channel = c->channelno | (c->ds1no << 8);
|
||||
pri->ev.hangup.cref = c->cr;
|
||||
pri->ev.hangup.cause = c->cause;
|
||||
pri->ev.hangup.call = c;
|
||||
@ -2338,7 +2354,7 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
||||
case Q931_RELEASE_COMPLETE:
|
||||
c->ourcallstate = Q931_CALL_STATE_NULL;
|
||||
c->peercallstate = Q931_CALL_STATE_NULL;
|
||||
pri->ev.hangup.channel = c->channelno;
|
||||
pri->ev.hangup.channel = c->channelno | (c->ds1no << 8);
|
||||
pri->ev.hangup.cref = c->cr;
|
||||
pri->ev.hangup.cause = c->cause;
|
||||
pri->ev.hangup.call = c;
|
||||
@ -2370,7 +2386,7 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
||||
}
|
||||
c->ourcallstate = Q931_CALL_STATE_NULL;
|
||||
pri->ev.e = PRI_EVENT_HANGUP;
|
||||
pri->ev.hangup.channel = c->channelno;
|
||||
pri->ev.hangup.channel = c->channelno | (c->ds1no << 8);
|
||||
pri->ev.hangup.cref = c->cr;
|
||||
pri->ev.hangup.cause = c->cause;
|
||||
pri->ev.hangup.call = c;
|
||||
@ -2395,7 +2411,7 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
||||
c->sendhangupack = 1;
|
||||
/* Return such an event */
|
||||
pri->ev.e = PRI_EVENT_HANGUP_REQ;
|
||||
pri->ev.hangup.channel = c->channelno;
|
||||
pri->ev.hangup.channel = c->channelno | (c->ds1no << 8);
|
||||
pri->ev.hangup.cref = c->cr;
|
||||
pri->ev.hangup.cause = c->cause;
|
||||
pri->ev.hangup.call = c;
|
||||
@ -2408,7 +2424,7 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
||||
c->ourcallstate = Q931_CALL_STATE_NULL;
|
||||
c->peercallstate = Q931_CALL_STATE_NULL;
|
||||
pri->ev.e = PRI_EVENT_RESTART_ACK;
|
||||
pri->ev.restartack.channel = c->channelno;
|
||||
pri->ev.restartack.channel = c->channelno | (c->ds1no << 8);
|
||||
return Q931_RES_HAVEEVENT;
|
||||
case Q931_INFORMATION:
|
||||
/* XXX We're handling only INFORMATION messages that contain
|
||||
@ -2423,7 +2439,7 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
||||
break;
|
||||
pri->ev.e = PRI_EVENT_INFO_RECEIVED;
|
||||
pri->ev.ring.call = c;
|
||||
pri->ev.ring.channel = c->channelno;
|
||||
pri->ev.ring.channel = c->channelno | (c->ds1no << 8);
|
||||
strncpy(pri->ev.ring.callednum, c->callednum, sizeof(pri->ev.ring.callednum) - 1);
|
||||
pri->ev.ring.complete = c->complete; /* this covers IE 33 (Sending Complete) */
|
||||
return Q931_RES_HAVEEVENT;
|
||||
@ -2474,3 +2490,17 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int q931_call_getcrv(struct pri *pri, q931_call *call, int *callmode)
|
||||
{
|
||||
if (callmode)
|
||||
*callmode = call->cr & 0x7;
|
||||
return ((call->cr & 0x7fff) >> 3);
|
||||
}
|
||||
|
||||
int q931_call_setcrv(struct pri *pri, q931_call *call, int crv, int callmode)
|
||||
{
|
||||
call->cr = (crv << 3) & 0x7fff;
|
||||
call->cr |= (callmode & 0x7);
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user