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:
Mark Spencer 2004-06-05 06:50:55 +00:00
parent bce8bfb87f
commit f065327cc1
9 changed files with 233 additions and 87 deletions

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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