diff --git a/libpri.h b/libpri.h index 2b785f1..f1bec9f 100755 --- a/libpri.h +++ b/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 diff --git a/pri.c b/pri.c index c4839df..d1a26bb 100755 --- a/pri.c +++ b/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); +} diff --git a/pri_internal.h b/pri_internal.h index 502055d..8684697 100755 --- a/pri_internal.h +++ b/pri_internal.h @@ -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); diff --git a/pri_q921.h b/pri_q921.h index 0cd3409..6a7eb4a 100755 --- a/pri_q921.h +++ b/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 diff --git a/pri_q931.h b/pri_q931.h index f0f32d5..aa551a7 100755 --- a/pri_q931.h +++ b/pri_q931.h @@ -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, diff --git a/prisched.c b/prisched.c index e96d091..cc668ec 100755 --- a/prisched.c +++ b/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;xpri_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;xpri_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)) diff --git a/pritest.c b/pritest.c index b67aedc..aa68af3 100755 --- a/pritest.c +++ b/pritest.c @@ -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 */ diff --git a/q921.c b/q921.c index e5248ad..8c676b0 100755 --- a/q921.c +++ b/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 diff --git a/q931.c b/q931.c index 55d7271..e9ec4c1 100755 --- a/q931.c +++ b/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 that's not an error */ - if (missingmand && pri->localtype == PRI_NETWORK && mh->msg == Q931_SETUP) { - for (x=0;x 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; +}