Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ace221ca0 | ||
|
|
a7a2245b12 | ||
|
|
c038af7892 | ||
|
|
f8e6096bfe | ||
|
|
d2585d6da2 | ||
|
|
90019b935a | ||
|
|
c71499df29 | ||
|
|
2952e95715 | ||
|
|
7da3366cec | ||
|
|
734e922301 | ||
|
|
a9722804c1 | ||
|
|
6b2cc87b30 | ||
|
|
fc96191788 | ||
|
|
5fda3d8c68 | ||
|
|
af8a550ff9 | ||
|
|
a50516c1e4 | ||
|
|
998e6ba598 | ||
|
|
cfac266390 | ||
|
|
13beaacc80 | ||
|
|
84b2560da5 |
1
.cleancount
Normal file
1
.cleancount
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
12
.gitignore
vendored
Normal file
12
.gitignore
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
*.o
|
||||
*.o.d
|
||||
*.lo
|
||||
*.so
|
||||
*.a
|
||||
libpri.so.*
|
||||
pridump
|
||||
pritest
|
||||
rosetest
|
||||
testprilib
|
||||
version.c
|
||||
|
||||
4
.gitreview
Normal file
4
.gitreview
Normal file
@@ -0,0 +1,4 @@
|
||||
[gerrit]
|
||||
host=gerrit.asterisk.org
|
||||
port=29418
|
||||
project=libpri.git
|
||||
7
Makefile
7
Makefile
@@ -27,6 +27,8 @@
|
||||
CC=gcc
|
||||
GREP=grep
|
||||
AWK=awk
|
||||
AR=ar
|
||||
RANLIB=ranlib
|
||||
|
||||
OSARCH=$(shell uname -s)
|
||||
PROC?=$(shell uname -m)
|
||||
@@ -67,6 +69,7 @@ STATIC_OBJS= \
|
||||
DYNAMIC_OBJS= \
|
||||
$(STATIC_OBJS)
|
||||
CFLAGS ?= -g
|
||||
CFLAGS += $(CPPFLAGS)
|
||||
CFLAGS += -Wall -Werror -Wstrict-prototypes -Wmissing-prototypes
|
||||
CFLAGS += -fPIC $(ALERTING) $(LIBPRI_OPT) $(COVERAGE_CFLAGS)
|
||||
INSTALL_PREFIX=$(DESTDIR)
|
||||
@@ -192,8 +195,8 @@ MAKE_DEPS= -MD -MT $@ -MF .$(subst /,_,$@).d -MP
|
||||
$(CC) $(CFLAGS) $(MAKE_DEPS) -c -o $@ $<
|
||||
|
||||
$(STATIC_LIBRARY): $(STATIC_OBJS)
|
||||
ar rcs $(STATIC_LIBRARY) $(STATIC_OBJS)
|
||||
ranlib $(STATIC_LIBRARY)
|
||||
$(AR) rcs $(STATIC_LIBRARY) $(STATIC_OBJS)
|
||||
$(RANLIB) $(STATIC_LIBRARY)
|
||||
|
||||
$(DYNAMIC_LIBRARY): $(DYNAMIC_OBJS)
|
||||
$(CC) $(SOFLAGS) -o $@ $(DYNAMIC_OBJS)
|
||||
|
||||
66
libpri.h
66
libpri.h
@@ -1213,6 +1213,7 @@ typedef struct pri_event_setup_ack {
|
||||
int channel;
|
||||
q931_call *call;
|
||||
struct pri_subcommands *subcmds;
|
||||
int progressmask;
|
||||
} pri_event_setup_ack;
|
||||
|
||||
typedef struct pri_event_notify {
|
||||
@@ -1408,8 +1409,17 @@ const char *pri_facility_error2str(int facility_error_code);
|
||||
*/
|
||||
const char *pri_facility_reject2str(int facility_reject_code);
|
||||
|
||||
/* Acknowledge a call and place it on the given channel. Set info to non-zero if there
|
||||
is in-band data available on the channel */
|
||||
/*!
|
||||
* \brief Send the ALERTING message.
|
||||
*
|
||||
* \param pri D channel controller.
|
||||
* \param call Q.931 call leg.
|
||||
* \param channel Encoded channel id to use. If zero do not change channel id.
|
||||
* \param info Nonzero to include a progress ie indicating inband audio available (ie ringback).
|
||||
*
|
||||
* \retval 0 on success.
|
||||
* \retval -1 on error.
|
||||
*/
|
||||
int pri_acknowledge(struct pri *pri, q931_call *call, int channel, int info);
|
||||
|
||||
/* Send a digit in overlap mode */
|
||||
@@ -1419,12 +1429,44 @@ int pri_information(struct pri *pri, q931_call *call, char digit);
|
||||
/* Send a keypad facility string of digits */
|
||||
int pri_keypad_facility(struct pri *pri, q931_call *call, const char *digits);
|
||||
|
||||
/* Answer the incomplete(call without called number) call on the given channel.
|
||||
Set non-isdn to non-zero if you are not connecting to ISDN equipment */
|
||||
/*!
|
||||
* \brief Send the SETUP_ACKNOWLEDGE message.
|
||||
*
|
||||
* \param pri D channel controller.
|
||||
* \param call Q.931 call leg.
|
||||
* \param channel Encoded channel id to use. If zero do not change channel id.
|
||||
* \param nonisdn Nonzero to include a progress ie indicating non-end-to-end-ISDN.
|
||||
*
|
||||
* \retval 0 on success.
|
||||
* \retval -1 on error.
|
||||
*/
|
||||
int pri_need_more_info(struct pri *pri, q931_call *call, int channel, int nonisdn);
|
||||
|
||||
/* Answer(CONNECT) the call on the given channel.
|
||||
Set non-isdn to non-zero if you are not connecting to ISDN equipment */
|
||||
/*!
|
||||
* \brief Send the SETUP_ACKNOWLEDGE message.
|
||||
*
|
||||
* \param ctrl D channel controller.
|
||||
* \param call Q.931 call leg.
|
||||
* \param channel Encoded channel id to use. If zero do not change channel id.
|
||||
* \param nonisdn Nonzero to include a progress ie indicating non-end-to-end-ISDN.
|
||||
* \param inband Nonzero to include a progress ie indicating inband audio available (ie dialtone).
|
||||
*
|
||||
* \retval 0 on success.
|
||||
* \retval -1 on error.
|
||||
*/
|
||||
int pri_setup_ack(struct pri *ctrl, q931_call *call, int channel, int nonisdn, int inband);
|
||||
|
||||
/*!
|
||||
* \brief Send the CONNECT message.
|
||||
*
|
||||
* \param pri D channel controller.
|
||||
* \param call Q.931 call leg.
|
||||
* \param channel Encoded channel id to use. If zero do not change channel id.
|
||||
* \param nonisdn Nonzero to include a progress ie indicating non-end-to-end-ISDN.
|
||||
*
|
||||
* \retval 0 on success.
|
||||
* \retval -1 on error.
|
||||
*/
|
||||
int pri_answer(struct pri *pri, q931_call *call, int channel, int nonisdn);
|
||||
|
||||
/*!
|
||||
@@ -1692,7 +1734,17 @@ int pri_progress(struct pri *pri, q931_call *c, int channel, int info);
|
||||
int pri_progress_with_cause(struct pri *pri, q931_call *c, int channel, int info, int cause);
|
||||
|
||||
#define PRI_PROCEEDING_FULL
|
||||
/* Send call proceeding */
|
||||
/*!
|
||||
* \brief Send the PROCEEDING message.
|
||||
*
|
||||
* \param pri D channel controller.
|
||||
* \param c Q.931 call leg.
|
||||
* \param channel Encoded channel id to use. If zero do not change channel id.
|
||||
* \param info Nonzero to include a progress ie indicating inband audio available.
|
||||
*
|
||||
* \retval 0 on success.
|
||||
* \retval -1 on error.
|
||||
*/
|
||||
int pri_proceeding(struct pri *pri, q931_call *c, int channel, int info);
|
||||
|
||||
/* Enable inband progress when a DISCONNECT is received */
|
||||
|
||||
12
pri.c
12
pri.c
@@ -176,7 +176,7 @@ static void pri_default_timers(struct pri *ctrl, int switchtype)
|
||||
|
||||
ctrl->timers[PRI_TIMER_T200] = 1000; /* Time between SABME's */
|
||||
ctrl->timers[PRI_TIMER_T201] = ctrl->timers[PRI_TIMER_T200];/* Time between TEI Identity Checks (Default same as T200) */
|
||||
ctrl->timers[PRI_TIMER_T202] = 10 * 1000; /* Min time between transmission of TEI Identity request messages */
|
||||
ctrl->timers[PRI_TIMER_T202] = 2 * 1000; /* Min time between transmission of TEI Identity request messages */
|
||||
ctrl->timers[PRI_TIMER_T203] = 10 * 1000; /* Max time without exchanging packets */
|
||||
|
||||
ctrl->timers[PRI_TIMER_T303] = 4 * 1000; /* Length between SETUP retransmissions and timeout */
|
||||
@@ -939,7 +939,15 @@ int pri_need_more_info(struct pri *pri, q931_call *call, int channel, int nonisd
|
||||
if (!pri || !pri_is_call_valid(pri, call)) {
|
||||
return -1;
|
||||
}
|
||||
return q931_setup_ack(pri, call, channel, nonisdn);
|
||||
return q931_setup_ack(pri, call, channel, nonisdn, 0);
|
||||
}
|
||||
|
||||
int pri_setup_ack(struct pri *ctrl, q931_call *call, int channel, int nonisdn, int inband)
|
||||
{
|
||||
if (!ctrl || !pri_is_call_valid(ctrl, call)) {
|
||||
return -1;
|
||||
}
|
||||
return q931_setup_ack(ctrl, call, channel, nonisdn, inband);
|
||||
}
|
||||
|
||||
int pri_answer(struct pri *pri, q931_call *call, int channel, int nonisdn)
|
||||
|
||||
@@ -647,10 +647,13 @@ struct q931_call {
|
||||
unsigned char char_set;
|
||||
} display;
|
||||
|
||||
/* AOC charge requesting on Setup */
|
||||
/*! AOC charge requesting on Setup */
|
||||
int aoc_charging_request;
|
||||
|
||||
unsigned int slotmap_size:1;/* TRUE if the slotmap is E1 (32 bits). */
|
||||
/*! TRUE if the slotmap is E1 (32 bits). */
|
||||
unsigned int slotmap_size:1;
|
||||
/*! TRUE if need to see the channel id ie in first response to SETUP. */
|
||||
unsigned int channel_id_ie_mandatory:1;
|
||||
|
||||
/*! Control the RESTART reception to the upper layer. */
|
||||
struct {
|
||||
|
||||
@@ -138,9 +138,6 @@ typedef struct q931_ie {
|
||||
#define SERVICE_CHANGE_STATUS_REQCONTINUITYCHECK 3 /* not supported */
|
||||
#define SERVICE_CHANGE_STATUS_SHUTDOWN 4 /* not supported */
|
||||
|
||||
/* Special codeset 0 IE */
|
||||
#define NATIONAL_CHANGE_STATUS 0x1
|
||||
|
||||
/* Q.931 / National ISDN Information Elements */
|
||||
#define Q931_LOCKING_SHIFT 0x90
|
||||
#define Q931_NON_LOCKING_SHIFT 0x98
|
||||
@@ -468,7 +465,7 @@ extern int q931_notify(struct pri *pri, q931_call *call, int channel, int info);
|
||||
|
||||
extern int q931_call_proceeding(struct pri *pri, q931_call *call, int channel, int info);
|
||||
|
||||
extern int q931_setup_ack(struct pri *pri, q931_call *call, int channel, int nonisdn);
|
||||
extern int q931_setup_ack(struct pri *ctrl, q931_call *c, int channel, int nonisdn, int inband);
|
||||
|
||||
extern int q931_information(struct pri *pri, q931_call *call, char digit);
|
||||
|
||||
|
||||
214
q921.c
214
q921.c
@@ -45,13 +45,19 @@
|
||||
*/
|
||||
//#define RANDOM_DROPS 1
|
||||
|
||||
#define Q921_INIT(link, hf) do { \
|
||||
memset(&(hf),0,sizeof(hf)); \
|
||||
(hf).h.sapi = (link)->sapi; \
|
||||
(hf).h.ea1 = 0; \
|
||||
(hf).h.ea2 = 1; \
|
||||
(hf).h.tei = (link)->tei; \
|
||||
} while (0)
|
||||
#define Q921_INIT(fr, l_sapi, l_tei) \
|
||||
do { \
|
||||
(fr)->h.sapi = l_sapi; \
|
||||
(fr)->h.ea1 = 0; \
|
||||
(fr)->h.ea2 = 1; \
|
||||
(fr)->h.tei = l_tei; \
|
||||
} while (0)
|
||||
|
||||
#define Q921_CLEAR_INIT(fr, l_sapi, l_tei) \
|
||||
do { \
|
||||
memset((fr), 0, sizeof(*(fr))); \
|
||||
Q921_INIT((fr), (l_sapi), (l_tei)); \
|
||||
} while (0)
|
||||
|
||||
static void q921_dump_pri(struct q921_link *link, char direction_tag);
|
||||
static void q921_establish_data_link(struct q921_link *link);
|
||||
@@ -196,17 +202,14 @@ static int q921_transmit(struct pri *ctrl, q921_h *h, int len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void q921_send_tei(struct pri *ctrl, enum q921_tei_identity message, int ri, int ai, int iscommand)
|
||||
static void q921_mdl_send(struct pri *ctrl, enum q921_tei_identity message, int ri, int ai, int iscommand)
|
||||
{
|
||||
q921_u *f;
|
||||
struct q921_link *link;
|
||||
|
||||
link = &ctrl->link;
|
||||
|
||||
if (!(f = calloc(1, sizeof(*f) + 5)))
|
||||
return;
|
||||
|
||||
Q921_INIT(link, *f);
|
||||
Q921_INIT(f, Q921_SAPI_LAYER2_MANAGEMENT, Q921_TEI_GROUP);
|
||||
f->h.c_r = (ctrl->localtype == PRI_NETWORK) ? iscommand : !iscommand;
|
||||
f->ft = Q921_FRAMETYPE_U;
|
||||
f->data[0] = 0x0f; /* Management entity */
|
||||
@@ -216,7 +219,7 @@ static void q921_send_tei(struct pri *ctrl, enum q921_tei_identity message, int
|
||||
f->data[4] = (ai << 1) | 1;
|
||||
if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
|
||||
pri_message(ctrl,
|
||||
"Sending TEI management message %d(%s), TEI=%d\n",
|
||||
"Sending MDL message: %d(%s), TEI=%d\n",
|
||||
message, q921_tei_mgmt2str(message), ai);
|
||||
}
|
||||
q921_transmit(ctrl, (q921_h *)f, 8);
|
||||
@@ -265,7 +268,7 @@ static void t202_expire(void *vlink)
|
||||
|
||||
/* Send TEI request */
|
||||
link->ri = random() % 65535;
|
||||
q921_send_tei(ctrl, Q921_TEI_IDENTITY_REQUEST, link->ri, Q921_TEI_GROUP, 1);
|
||||
q921_mdl_send(ctrl, Q921_TEI_IDENTITY_REQUEST, link->ri, Q921_TEI_GROUP, 1);
|
||||
}
|
||||
|
||||
static void q921_tei_request(struct q921_link *link)
|
||||
@@ -280,8 +283,8 @@ static void q921_tei_remove(struct pri *ctrl, int tei)
|
||||
* Q.921 Section 5.3.2 says we should send the remove message
|
||||
* twice, in case of message loss.
|
||||
*/
|
||||
q921_send_tei(ctrl, Q921_TEI_IDENTITY_REMOVE, 0, tei, 1);
|
||||
q921_send_tei(ctrl, Q921_TEI_IDENTITY_REMOVE, 0, tei, 1);
|
||||
q921_mdl_send(ctrl, Q921_TEI_IDENTITY_REMOVE, 0, tei, 1);
|
||||
q921_mdl_send(ctrl, Q921_TEI_IDENTITY_REMOVE, 0, tei, 1);
|
||||
}
|
||||
|
||||
static void q921_send_dm(struct q921_link *link, int fbit)
|
||||
@@ -291,7 +294,7 @@ static void q921_send_dm(struct q921_link *link, int fbit)
|
||||
|
||||
ctrl = link->ctrl;
|
||||
|
||||
Q921_INIT(link, h);
|
||||
Q921_CLEAR_INIT(&h, link->sapi, link->tei);
|
||||
h.u.m3 = 0; /* M3 = 0 */
|
||||
h.u.m2 = 3; /* M2 = 3 */
|
||||
h.u.p_f = fbit; /* Final set appropriately */
|
||||
@@ -310,7 +313,7 @@ static void q921_send_dm(struct q921_link *link, int fbit)
|
||||
if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
|
||||
pri_message(ctrl, "TEI=%d Sending DM\n", link->tei);
|
||||
}
|
||||
q921_transmit(ctrl, &h, 4);
|
||||
q921_transmit(ctrl, &h, 3);
|
||||
}
|
||||
|
||||
static void q921_send_disc(struct q921_link *link, int pbit)
|
||||
@@ -320,7 +323,7 @@ static void q921_send_disc(struct q921_link *link, int pbit)
|
||||
|
||||
ctrl = link->ctrl;
|
||||
|
||||
Q921_INIT(link, h);
|
||||
Q921_CLEAR_INIT(&h, link->sapi, link->tei);
|
||||
h.u.m3 = 2; /* M3 = 2 */
|
||||
h.u.m2 = 0; /* M2 = 0 */
|
||||
h.u.p_f = pbit; /* Poll set appropriately */
|
||||
@@ -339,7 +342,7 @@ static void q921_send_disc(struct q921_link *link, int pbit)
|
||||
if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
|
||||
pri_message(ctrl, "TEI=%d Sending DISC\n", link->tei);
|
||||
}
|
||||
q921_transmit(ctrl, &h, 4);
|
||||
q921_transmit(ctrl, &h, 3);
|
||||
}
|
||||
|
||||
static void q921_send_ua(struct q921_link *link, int fbit)
|
||||
@@ -349,7 +352,7 @@ static void q921_send_ua(struct q921_link *link, int fbit)
|
||||
|
||||
ctrl = link->ctrl;
|
||||
|
||||
Q921_INIT(link, h);
|
||||
Q921_CLEAR_INIT(&h, link->sapi, link->tei);
|
||||
h.u.m3 = 3; /* M3 = 3 */
|
||||
h.u.m2 = 0; /* M2 = 0 */
|
||||
h.u.p_f = fbit; /* Final set appropriately */
|
||||
@@ -378,7 +381,7 @@ static void q921_send_sabme(struct q921_link *link)
|
||||
|
||||
ctrl = link->ctrl;
|
||||
|
||||
Q921_INIT(link, h);
|
||||
Q921_CLEAR_INIT(&h, link->sapi, link->tei);
|
||||
h.u.m3 = 3; /* M3 = 3 */
|
||||
h.u.m2 = 3; /* M2 = 3 */
|
||||
h.u.p_f = 1; /* Poll bit set */
|
||||
@@ -557,7 +560,7 @@ static void kick_start_link(struct q921_link *link)
|
||||
break;
|
||||
case Q921_ASSIGN_AWAITING_TEI:
|
||||
if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
|
||||
pri_message(ctrl, "Kick starting link when get TEI.\n");
|
||||
pri_message(ctrl, "Kick starting link when awaiting TEI.\n");
|
||||
}
|
||||
q921_setstate(link, Q921_ESTABLISH_AWAITING_TEI);
|
||||
break;
|
||||
@@ -586,6 +589,8 @@ static void restart_timer_expire(void *vlink)
|
||||
link->restart_timer = 0;
|
||||
|
||||
switch (link->state) {
|
||||
case Q921_TEI_UNASSIGNED:
|
||||
case Q921_ASSIGN_AWAITING_TEI:
|
||||
case Q921_TEI_ASSIGNED:
|
||||
/* Try to bring layer 2 up. */
|
||||
kick_start_link(link);
|
||||
@@ -807,7 +812,7 @@ static void q921_reject(struct q921_link *link, int pf)
|
||||
|
||||
ctrl = link->ctrl;
|
||||
|
||||
Q921_INIT(link, h);
|
||||
Q921_CLEAR_INIT(&h, link->sapi, link->tei);
|
||||
h.s.x0 = 0; /* Always 0 */
|
||||
h.s.ss = 2; /* Reject */
|
||||
h.s.ft = 1; /* Frametype (01) */
|
||||
@@ -837,7 +842,7 @@ static void q921_rr(struct q921_link *link, int pbit, int cmd)
|
||||
|
||||
ctrl = link->ctrl;
|
||||
|
||||
Q921_INIT(link, h);
|
||||
Q921_CLEAR_INIT(&h, link->sapi, link->tei);
|
||||
h.s.x0 = 0; /* Always 0 */
|
||||
h.s.ss = 0; /* Receive Ready */
|
||||
h.s.ft = 1; /* Frametype (01) */
|
||||
@@ -1064,7 +1069,7 @@ int q921_transmit_iframe(struct q921_link *link, void *buf, int len, int cr)
|
||||
|
||||
f = calloc(1, sizeof(struct q921_frame) + len + 2);
|
||||
if (f) {
|
||||
Q921_INIT(link, f->h);
|
||||
Q921_INIT(&f->h, link->sapi, link->tei);
|
||||
switch (ctrl->localtype) {
|
||||
case PRI_NETWORK:
|
||||
if (cr)
|
||||
@@ -1394,12 +1399,6 @@ static void t201_expire(void *vctrl)
|
||||
|
||||
ctrl = vctrl;
|
||||
|
||||
if (!ctrl->link.next) {
|
||||
/* No TEI links remain. */
|
||||
ctrl->t201_timer = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Start the TEI check timer. */
|
||||
ctrl->t201_timer =
|
||||
pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T201], t201_expire, ctrl);
|
||||
@@ -1460,7 +1459,7 @@ static void t201_expire(void *vctrl)
|
||||
}
|
||||
}
|
||||
}
|
||||
q921_send_tei(ctrl, Q921_TEI_IDENTITY_CHECK_REQUEST, 0, Q921_TEI_GROUP, 1);
|
||||
q921_mdl_send(ctrl, Q921_TEI_IDENTITY_CHECK_REQUEST, 0, Q921_TEI_GROUP, 1);
|
||||
}
|
||||
|
||||
static void q921_tei_check(struct pri *ctrl)
|
||||
@@ -1473,7 +1472,19 @@ static void q921_tei_check(struct pri *ctrl)
|
||||
t201_expire(ctrl);
|
||||
}
|
||||
|
||||
static pri_event *q921_receive_MDL(struct pri *ctrl, q921_u *h, int len)
|
||||
static void q921_mdl_ignore(struct pri *ctrl, q921_u *h, const char *reason)
|
||||
{
|
||||
if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
|
||||
/*
|
||||
* Send out this message in debug modes since it is possible the
|
||||
* user has misconfigured their link for the wrong mode.
|
||||
*/
|
||||
pri_message(ctrl, "Ignoring MDL message: %d(%s) %s\n",
|
||||
h->data[3], q921_tei_mgmt2str(h->data[3]), reason);
|
||||
}
|
||||
}
|
||||
|
||||
static pri_event *q921_mdl_receive(struct pri *ctrl, q921_u *h, int len)
|
||||
{
|
||||
int ri;
|
||||
struct q921_link *sub;
|
||||
@@ -1483,32 +1494,13 @@ static pri_event *q921_receive_MDL(struct pri *ctrl, q921_u *h, int len)
|
||||
int count;
|
||||
int tei;
|
||||
|
||||
if (!BRI_NT_PTMP(ctrl) && !BRI_TE_PTMP(ctrl)) {
|
||||
/*
|
||||
* Some telco switches send out MDL messages even though they
|
||||
* are configured for PTP. Usually they are checking for
|
||||
* assigned TEI's.
|
||||
*/
|
||||
if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
|
||||
/*
|
||||
* Send out this message in debug modes since it is possible the
|
||||
* user has misconfigured their link for the wrong mode.
|
||||
*/
|
||||
pri_message(ctrl, "Not configured for PTMP. Ignoring MDL message: %d(%s)\n",
|
||||
h->data[3], q921_tei_mgmt2str(h->data[3]));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
|
||||
pri_message(ctrl, "Received MDL message\n");
|
||||
}
|
||||
if (len <= &h->data[0] - (u_int8_t *) h) {
|
||||
pri_error(ctrl, "Received short frame\n");
|
||||
pri_error(ctrl, "Received short MDL frame\n");
|
||||
return NULL;
|
||||
}
|
||||
if (h->data[0] != 0x0f) {
|
||||
pri_error(ctrl, "Received MDL with unsupported management entity %02x\n", h->data[0]);
|
||||
pri_error(ctrl, "Received MDL with unsupported management entity %02x\n",
|
||||
h->data[0]);
|
||||
return NULL;
|
||||
}
|
||||
if (len <= &h->data[4] - (u_int8_t *) h) {
|
||||
@@ -1517,8 +1509,20 @@ static pri_event *q921_receive_MDL(struct pri *ctrl, q921_u *h, int len)
|
||||
}
|
||||
if (h->data[3] != Q921_TEI_IDENTITY_CHECK_RESPONSE
|
||||
&& !(h->data[4] & 0x01)) {
|
||||
pri_error(ctrl, "Received %d(%s) with Ai E bit not set.\n", h->data[3],
|
||||
q921_tei_mgmt2str(h->data[3]));
|
||||
pri_error(ctrl, "Received MDL message: %d(%s) with Ai E bit not set.\n",
|
||||
h->data[3], q921_tei_mgmt2str(h->data[3]));
|
||||
return NULL;
|
||||
}
|
||||
if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
|
||||
pri_message(ctrl, "Received MDL message: %d(%s)\n",
|
||||
h->data[3], q921_tei_mgmt2str(h->data[3]));
|
||||
}
|
||||
if (PTP_MODE(ctrl) && NT_MODE(ctrl)) {
|
||||
/*
|
||||
* We are not managing automatic TEI's in this mode so we can
|
||||
* ignore MDL messages from the CPE.
|
||||
*/
|
||||
q921_mdl_ignore(ctrl, h, "We are in NT-PTP mode.");
|
||||
return NULL;
|
||||
}
|
||||
ri = (h->data[1] << 8) | h->data[2];
|
||||
@@ -1527,13 +1531,14 @@ static pri_event *q921_receive_MDL(struct pri *ctrl, q921_u *h, int len)
|
||||
switch (h->data[3]) {
|
||||
case Q921_TEI_IDENTITY_REQUEST:
|
||||
if (!BRI_NT_PTMP(ctrl)) {
|
||||
q921_mdl_ignore(ctrl, h, "We are not in NT-PTMP mode.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (tei != Q921_TEI_GROUP) {
|
||||
pri_error(ctrl, "Received %s with invalid TEI %d\n",
|
||||
q921_tei_mgmt2str(Q921_TEI_IDENTITY_REQUEST), tei);
|
||||
q921_send_tei(ctrl, Q921_TEI_IDENTITY_DENIED, ri, tei, 1);
|
||||
q921_mdl_send(ctrl, Q921_TEI_IDENTITY_DENIED, ri, tei, 1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1548,7 +1553,7 @@ static pri_event *q921_receive_MDL(struct pri *ctrl, q921_u *h, int len)
|
||||
break;
|
||||
}
|
||||
pri_error(ctrl, "TEI pool exhausted. Reclaiming dead TEIs.\n");
|
||||
q921_send_tei(ctrl, Q921_TEI_IDENTITY_DENIED, ri, Q921_TEI_GROUP, 1);
|
||||
q921_mdl_send(ctrl, Q921_TEI_IDENTITY_DENIED, ri, Q921_TEI_GROUP, 1);
|
||||
q921_tei_check(ctrl);
|
||||
return NULL;
|
||||
}
|
||||
@@ -1565,7 +1570,7 @@ static pri_event *q921_receive_MDL(struct pri *ctrl, q921_u *h, int len)
|
||||
}
|
||||
sub->next = link;
|
||||
q921_setstate(link, Q921_TEI_ASSIGNED);
|
||||
q921_send_tei(ctrl, Q921_TEI_IDENTITY_ASSIGNED, ri, tei, 1);
|
||||
q921_mdl_send(ctrl, Q921_TEI_IDENTITY_ASSIGNED, ri, tei, 1);
|
||||
|
||||
count = 0;
|
||||
for (sub = ctrl->link.next; sub; sub = sub->next) {
|
||||
@@ -1593,6 +1598,7 @@ static pri_event *q921_receive_MDL(struct pri *ctrl, q921_u *h, int len)
|
||||
break;
|
||||
case Q921_TEI_IDENTITY_CHECK_RESPONSE:
|
||||
if (!BRI_NT_PTMP(ctrl)) {
|
||||
/* Silently ignore the message since we never asked for the check. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1640,6 +1646,7 @@ static pri_event *q921_receive_MDL(struct pri *ctrl, q921_u *h, int len)
|
||||
break;
|
||||
case Q921_TEI_IDENTITY_VERIFY:
|
||||
if (!BRI_NT_PTMP(ctrl)) {
|
||||
q921_mdl_ignore(ctrl, h, "We are not in NT-PTMP mode.");
|
||||
return NULL;
|
||||
}
|
||||
if (tei == Q921_TEI_GROUP) {
|
||||
@@ -1650,11 +1657,20 @@ static pri_event *q921_receive_MDL(struct pri *ctrl, q921_u *h, int len)
|
||||
q921_tei_check(ctrl);
|
||||
break;
|
||||
case Q921_TEI_IDENTITY_ASSIGNED:
|
||||
if (NT_MODE(ctrl)) {
|
||||
/* We should not be receiving this message. */
|
||||
q921_mdl_ignore(ctrl, h, "We are the network.");
|
||||
return NULL;
|
||||
}
|
||||
if (!BRI_TE_PTMP(ctrl)) {
|
||||
/*
|
||||
* Silently ignore the message. It must not be for us
|
||||
* since we will never ask for one.
|
||||
*/
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Assuming we're operating on the specific TEI link here */
|
||||
/* We're operating on the specific TEI link here */
|
||||
link = ctrl->link.next;
|
||||
|
||||
switch (link->state) {
|
||||
@@ -1724,29 +1740,52 @@ static pri_event *q921_receive_MDL(struct pri *ctrl, q921_u *h, int len)
|
||||
}
|
||||
break;
|
||||
case Q921_TEI_IDENTITY_CHECK_REQUEST:
|
||||
if (!BRI_TE_PTMP(ctrl)) {
|
||||
if (NT_MODE(ctrl)) {
|
||||
/* We should not be receiving this message. */
|
||||
q921_mdl_ignore(ctrl, h, "We are the network.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Assuming we're operating on the specific TEI link here */
|
||||
link = ctrl->link.next;
|
||||
if (PTP_MODE(ctrl)) {
|
||||
/*
|
||||
* Some telco switches/devices get very unhappy if we don't
|
||||
* respond to the TEI check request with our permanently
|
||||
* assigned TEI.
|
||||
*/
|
||||
link = &ctrl->link;
|
||||
} else if (BRI_TE_PTMP(ctrl)) {
|
||||
/* We're operating on the specific TEI link here */
|
||||
link = ctrl->link.next;
|
||||
|
||||
if (link->state < Q921_TEI_ASSIGNED) {
|
||||
/* We do not have a TEI. */
|
||||
if (link->state < Q921_TEI_ASSIGNED) {
|
||||
/* We do not have a TEI. */
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
/* Should never get here. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* If it's addressed to the group TEI or to our TEI specifically, we respond */
|
||||
if (tei == Q921_TEI_GROUP || tei == link->tei) {
|
||||
q921_send_tei(ctrl, Q921_TEI_IDENTITY_CHECK_RESPONSE, random() % 65535, link->tei, 1);
|
||||
q921_mdl_send(ctrl, Q921_TEI_IDENTITY_CHECK_RESPONSE, random() % 65535, link->tei, 1);
|
||||
}
|
||||
break;
|
||||
case Q921_TEI_IDENTITY_REMOVE:
|
||||
if (NT_MODE(ctrl)) {
|
||||
/* We should not be receiving this message. */
|
||||
q921_mdl_ignore(ctrl, h, "We are the network.");
|
||||
return NULL;
|
||||
}
|
||||
if (!BRI_TE_PTMP(ctrl)) {
|
||||
/*
|
||||
* Silently ignore the message. If we are TE-PTP our
|
||||
* TEI is permanently assigned and cannot be removed.
|
||||
*/
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Assuming we're operating on the specific TEI link here */
|
||||
/* We're operating on the specific TEI link here */
|
||||
link = ctrl->link.next;
|
||||
|
||||
if (link->state < Q921_TEI_ASSIGNED) {
|
||||
@@ -1911,7 +1950,9 @@ static void q921_mdl_remove(struct q921_link *link)
|
||||
|
||||
switch (link->state) {
|
||||
case Q921_TEI_ASSIGNED:
|
||||
restart_timer_stop(link);
|
||||
if (mdl_free_me) {
|
||||
restart_timer_stop(link);
|
||||
}
|
||||
/* XXX: deviation! Since we don't have a UI queue, we just discard our I-queue */
|
||||
q921_discard_iqueue(link);
|
||||
q921_setstate(link, Q921_TEI_UNASSIGNED);
|
||||
@@ -2987,27 +3028,32 @@ static pri_event *__q921_receive_qualified(struct q921_link *link, q921_h *h, in
|
||||
|
||||
static pri_event *q921_handle_unmatched_frame(struct pri *ctrl, q921_h *h, int len)
|
||||
{
|
||||
if (h->h.tei < 64) {
|
||||
pri_error(ctrl, "Do not support manual TEI range. Discarding\n");
|
||||
if (!BRI_NT_PTMP(ctrl)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (h->h.tei < Q921_TEI_AUTO_FIRST) {
|
||||
if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
|
||||
pri_message(ctrl, "Manual TEI range is not supported in NT-PTMP mode. Discarding\n");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (h->h.sapi != Q921_SAPI_CALL_CTRL) {
|
||||
pri_error(ctrl, "Message with SAPI other than CALL CTRL is discarded\n");
|
||||
if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
|
||||
pri_message(ctrl, "Message with SAPI other than CALL CTRL is discarded\n");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* If we're NT-PTMP, this means an unrecognized TEI that we'll kill */
|
||||
if (BRI_NT_PTMP(ctrl)) {
|
||||
if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
|
||||
pri_message(ctrl,
|
||||
"Could not find a layer 2 link for received frame with SAPI/TEI of %d/%d.\n",
|
||||
h->h.sapi, h->h.tei);
|
||||
pri_message(ctrl, "Sending TEI release, in order to re-establish TEI state\n");
|
||||
}
|
||||
|
||||
q921_tei_remove(ctrl, h->h.tei);
|
||||
/* This means an unrecognized TEI that we'll kill */
|
||||
if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
|
||||
pri_message(ctrl,
|
||||
"Could not find a layer 2 link for received frame with SAPI/TEI of %d/%d.\n",
|
||||
h->h.sapi, h->h.tei);
|
||||
pri_message(ctrl, "Sending TEI release, in order to re-establish TEI state\n");
|
||||
}
|
||||
q921_tei_remove(ctrl, h->h.tei);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -3031,7 +3077,7 @@ static pri_event *__q921_receive(struct pri *ctrl, q921_h *h, int len)
|
||||
}
|
||||
|
||||
if (h->h.sapi == Q921_SAPI_LAYER2_MANAGEMENT) {
|
||||
return q921_receive_MDL(ctrl, &h->u, len);
|
||||
return q921_mdl_receive(ctrl, &h->u, len);
|
||||
}
|
||||
|
||||
if (h->h.tei == Q921_TEI_GROUP && h->h.sapi != Q921_SAPI_CALL_CTRL) {
|
||||
|
||||
545
q931.c
545
q931.c
@@ -40,6 +40,12 @@
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
|
||||
enum mandatory_ie_status {
|
||||
MAND_STATUS_OK,
|
||||
MAND_STATUS_CONTENT_ERROR,
|
||||
MAND_STATUS_MISSING,
|
||||
};
|
||||
|
||||
#define MAX_MAND_IES 10
|
||||
|
||||
struct msgtype {
|
||||
@@ -50,13 +56,27 @@ struct msgtype {
|
||||
|
||||
static struct msgtype msgs[] = {
|
||||
/* Call establishment messages */
|
||||
{ Q931_ALERTING, "ALERTING" },
|
||||
{ Q931_CALL_PROCEEDING, "CALL PROCEEDING" },
|
||||
{ Q931_CONNECT, "CONNECT" },
|
||||
{ Q931_ALERTING, "ALERTING", { Q931_CHANNEL_IDENT } },
|
||||
{ Q931_CALL_PROCEEDING, "CALL PROCEEDING", { Q931_CHANNEL_IDENT } },
|
||||
{ Q931_CONNECT, "CONNECT", { Q931_CHANNEL_IDENT } },
|
||||
{ Q931_CONNECT_ACKNOWLEDGE, "CONNECT ACKNOWLEDGE" },
|
||||
/*
|
||||
* Very early in libpri SVN history (SVN -r154) a change was explicitly
|
||||
* made to not care about a missing Progress Indicator ie. There is no
|
||||
* explanation in the commit message why this was done even though
|
||||
* Q.931 and ECMA-143 clearly show that the ie is mandatory for a
|
||||
* PROGRESS message.
|
||||
*
|
||||
* Hazzarding a guess, I think it was because of the
|
||||
* ALERTING_NO_PROGRESS support for Mitel switches. (SVN -r44)
|
||||
*/
|
||||
#ifdef ALERTING_NO_PROGRESS
|
||||
{ Q931_PROGRESS, "PROGRESS" },
|
||||
#else
|
||||
{ Q931_PROGRESS, "PROGRESS", { Q931_PROGRESS_INDICATOR } },
|
||||
#endif
|
||||
{ Q931_SETUP, "SETUP", { Q931_BEARER_CAPABILITY, Q931_CHANNEL_IDENT } },
|
||||
{ Q931_SETUP_ACKNOWLEDGE, "SETUP ACKNOWLEDGE" },
|
||||
{ Q931_SETUP_ACKNOWLEDGE, "SETUP ACKNOWLEDGE", { Q931_CHANNEL_IDENT } },
|
||||
|
||||
/* Call disestablishment messages */
|
||||
{ Q931_DISCONNECT, "DISCONNECT", { Q931_CAUSE } },
|
||||
@@ -93,7 +113,7 @@ static struct msgtype msgs[] = {
|
||||
{ Q931_ANY_MESSAGE, "ANY MESSAGE" },
|
||||
};
|
||||
|
||||
static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct q931_call *c, int missingmand);
|
||||
static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct q931_call *c, enum mandatory_ie_status mand_status);
|
||||
static void nt_ptmp_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct q931_call *c, int *allow_event, int *allow_posthandle);
|
||||
|
||||
struct msgtype att_maintenance_msgs[] = {
|
||||
@@ -1258,6 +1278,14 @@ static int receive_channel_id(int full_ie, struct pri *ctrl, q931_call *call, in
|
||||
int pos = 0;
|
||||
int need_extended_channel_octets;/*!< TRUE if octets 3.2 and 3.3 need to be present. */
|
||||
|
||||
call->channel_id_ie_mandatory = 0;
|
||||
|
||||
if (ie->len < 1) {
|
||||
/* Must have at least one payload octet. */
|
||||
pri_error(ctrl, "!! Channel Identification ie too short\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
call->restart.count = 0;
|
||||
|
||||
if (ie->data[0] & 0x08) {
|
||||
@@ -1308,10 +1336,24 @@ static int receive_channel_id(int full_ie, struct pri *ctrl, q931_call *call, in
|
||||
|
||||
pos++;
|
||||
if (ie->data[0] & 0x40) {
|
||||
/* DS1 specified -- stop here */
|
||||
call->ds1no = ie->data[1] & 0x7f;
|
||||
/* Explicitly defined DS1 (One or more 3.1 octets expected) */
|
||||
if (ctrl->switchtype == PRI_SWITCH_QSIG) {
|
||||
pri_error(ctrl, "!! Q.SIG does not support Channel Identification octet 3.1\n");
|
||||
return -1;
|
||||
}
|
||||
if (ie->len <= pos) {
|
||||
pri_error(ctrl, "!! Missing expected Channel Identification octet 3.1\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Extract explicit DS1 reference. */
|
||||
call->ds1no = ie->data[pos] & 0x7f;
|
||||
call->ds1explicit = 1;
|
||||
pos++;
|
||||
|
||||
/* Advance to 3.2 octet if present. */
|
||||
do {
|
||||
++pos;
|
||||
} while (pos < ie->len && !(ie->data[pos - 1] & 0x80));
|
||||
} else {
|
||||
call->ds1explicit = 0;
|
||||
}
|
||||
@@ -1324,8 +1366,12 @@ static int receive_channel_id(int full_ie, struct pri *ctrl, q931_call *call, in
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (need_extended_channel_octets && pos + 2 < len) {
|
||||
/* More coming */
|
||||
if (need_extended_channel_octets && pos + 2 <= ie->len) {
|
||||
/*
|
||||
* Octet 3.2 and at least one octet 3.3 are present.
|
||||
*
|
||||
* Process octet 3.2
|
||||
*/
|
||||
if ((ie->data[pos] & 0x0f) != 3) {
|
||||
/* Channel type/mapping is not for B channel units. */
|
||||
pri_error(ctrl, "!! Unexpected Channel Type %d\n", ie->data[pos] & 0x0f);
|
||||
@@ -1335,14 +1381,25 @@ static int receive_channel_id(int full_ie, struct pri *ctrl, q931_call *call, in
|
||||
pri_error(ctrl, "!! Invalid CCITT coding %d\n", (ie->data[pos] & 0x60) >> 5);
|
||||
return -1;
|
||||
}
|
||||
if (ie->data[pos] & 0x10) {
|
||||
/* Expect Slot Map */
|
||||
if (ie->data[pos++] & 0x10) {
|
||||
/* Process 3.3 octets as a Slot Map */
|
||||
call->slotmap = 0;
|
||||
pos++;
|
||||
call->slotmap_size = (ie->len - pos > 3) ? 1 : 0;
|
||||
for (x = 0; x < (call->slotmap_size ? 4 : 3); ++x) {
|
||||
|
||||
/*
|
||||
* We will be tolerant of partial slot maps that do not
|
||||
* specify the upper channels. We will assume they
|
||||
* are not requested.
|
||||
*
|
||||
* We will only read up to 24 or 32 bit channel maps.
|
||||
*/
|
||||
for (x = call->slotmap_size ? 4 : 3; x--;) {
|
||||
call->slotmap <<= 8;
|
||||
call->slotmap |= ie->data[x + pos];
|
||||
call->slotmap |= ie->data[pos++];
|
||||
if (ie->len <= pos) {
|
||||
/* No more ie contents. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (msgtype == Q931_RESTART) {
|
||||
@@ -1357,8 +1414,11 @@ static int receive_channel_id(int full_ie, struct pri *ctrl, q931_call *call, in
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pos++;
|
||||
/* Only expect a particular channel */
|
||||
/*
|
||||
* Process 3.3 octets as either a single channel or a channel list
|
||||
*
|
||||
* Get single channel
|
||||
*/
|
||||
call->channelno = ie->data[pos] & 0x7f;
|
||||
if (ctrl->chan_mapping_logical && call->channelno > 15) {
|
||||
call->channelno++;
|
||||
@@ -1385,6 +1445,9 @@ static int receive_channel_id(int full_ie, struct pri *ctrl, q931_call *call, in
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (need_extended_channel_octets) {
|
||||
pri_error(ctrl, "!! Missing expected Channel Identification octets 3.2 or 3.3\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1518,21 +1581,29 @@ static void dump_channel_id(int full_ie, struct pri *ctrl, q931_ie *ie, int len,
|
||||
(ie->data[0] & 0x08) ? "Exclusive" : "Preferred",
|
||||
(ie->data[0] & 0x04) ? 1 : 0);
|
||||
pri_message(ctrl, "%c ChanSel: %s\n",
|
||||
prefix, msg_chan_sel[(ie->data[0] & 0x03) | ((ie->data[0] >> 3) & 0x04)]);
|
||||
prefix, msg_chan_sel[(ie->data[0] & 0x03) | ((ie->data[0] & 0x20) >> 3)]);
|
||||
pos = 1;
|
||||
len -= 2;
|
||||
if (ie->data[0] & 0x40) {
|
||||
/* Explicitly defined DS1 */
|
||||
do {
|
||||
pri_message(ctrl, "%c Ext: %d DS1 Identifier: %d \n",
|
||||
prefix, (ie->data[pos] & 0x80) >> 7, ie->data[pos] & 0x7f);
|
||||
++pos;
|
||||
} while (!(ie->data[pos - 1] & 0x80) && pos < len);
|
||||
/* Explicitly defined DS1 (One or more 3.1 octets expected) */
|
||||
if (ctrl->switchtype == PRI_SWITCH_QSIG) {
|
||||
pri_message(ctrl, "%c Octet 3.1 specified when Q.SIG!\n",
|
||||
prefix);
|
||||
}
|
||||
if (pos < len) {
|
||||
do {
|
||||
pri_message(ctrl, "%c Ext: %d DS1 Identifier: %d\n",
|
||||
prefix, (ie->data[pos] & 0x80) >> 7, ie->data[pos] & 0x7f);
|
||||
++pos;
|
||||
} while (!(ie->data[pos - 1] & 0x80) && pos < len);
|
||||
} else {
|
||||
pri_message(ctrl, "%c Octet 3.1 is missing!\n", prefix);
|
||||
}
|
||||
} else {
|
||||
/* Implicitly defined DS1 */
|
||||
}
|
||||
if (pos < len) {
|
||||
/* Still more information here */
|
||||
/* Octet 3.2 present */
|
||||
pri_message(ctrl,
|
||||
"%c Ext: %d Coding: %d %s Specified Channel Type: %d\n",
|
||||
prefix, (ie->data[pos] & 0x80) >> 7, (ie->data[pos] & 60) >> 5,
|
||||
@@ -1540,6 +1611,7 @@ static void dump_channel_id(int full_ie, struct pri *ctrl, q931_ie *ie, int len,
|
||||
++pos;
|
||||
}
|
||||
if (pos < len) {
|
||||
/* One or more 3.3 octets present */
|
||||
if (!(ie->data[pos - 1] & 0x10)) {
|
||||
/* Number specified */
|
||||
do {
|
||||
@@ -2124,17 +2196,33 @@ static int transmit_subaddr_helper(int full_ie, struct pri *ctrl, struct q931_pa
|
||||
|
||||
static int receive_subaddr_helper(int full_ie, struct pri *ctrl, struct q931_party_subaddress *q931_subaddress, int msgtype, q931_ie *ie, int offset, int len)
|
||||
{
|
||||
int i = -1;
|
||||
|
||||
if (len <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* To follow Q.931 (4.5.1), we must search for start of octet 4 by
|
||||
* walking through all bytes until one with ext bit (8) set to 1
|
||||
*/
|
||||
do {
|
||||
++i;
|
||||
switch (i) {
|
||||
case 0: /* Octet 3 */
|
||||
/* type: 0 = NSAP, 2 = User Specified */
|
||||
q931_subaddress->type = ((ie->data[0] & 0x70) >> 4);
|
||||
q931_subaddress->odd_even_indicator = (ie->data[0] & 0x08) ? 1 : 0;
|
||||
break;
|
||||
default: /* Octet 3* extra */
|
||||
break;
|
||||
}
|
||||
} while (!(ie->data[i] & 0x80) && len - i);
|
||||
|
||||
q931_subaddress->valid = 1;
|
||||
q931_subaddress->length = len;
|
||||
/* type: 0 = NSAP, 2 = User Specified */
|
||||
q931_subaddress->type = ((ie->data[0] & 0x70) >> 4);
|
||||
q931_subaddress->odd_even_indicator = (ie->data[0] & 0x08) ? 1 : 0;
|
||||
q931_subaddress->length = len - i;
|
||||
q931_memget(q931_subaddress->data, sizeof(q931_subaddress->data),
|
||||
ie->data + offset, len);
|
||||
ie->data + offset + i, len - i);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2142,13 +2230,22 @@ static int receive_subaddr_helper(int full_ie, struct pri *ctrl, struct q931_par
|
||||
static void dump_subaddr_helper(int full_ie, struct pri *ctrl, q931_ie *ie, int offset, int len, int datalen, char prefix)
|
||||
{
|
||||
unsigned char cnum[256];
|
||||
int i = -1;
|
||||
|
||||
/*
|
||||
* To follow Q.931 (4.5.1), we must search for start of octet 4 by
|
||||
* walking through all bytes until one with ext bit (8) set to 1
|
||||
*/
|
||||
do {
|
||||
++i;
|
||||
} while (!(ie->data[i] & 0x80) && datalen - i);
|
||||
|
||||
if (!(ie->data[0] & 0x70)) {
|
||||
/* NSAP Get it as a string for dump display purposes only. */
|
||||
q931_strget(cnum, sizeof(cnum), ie->data + offset, datalen);
|
||||
q931_strget(cnum, sizeof(cnum), ie->data + offset + i, datalen - i);
|
||||
} else {
|
||||
/* User Specified */
|
||||
q931_get_subaddr_specific(cnum, sizeof(cnum), ie->data + offset, datalen,
|
||||
q931_get_subaddr_specific(cnum, sizeof(cnum), ie->data + offset + i, datalen - i,
|
||||
ie->data[0] & 0x08);
|
||||
}
|
||||
|
||||
@@ -2268,6 +2365,7 @@ static int receive_connected_number(int full_ie, struct pri *ctrl, q931_call *ca
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
/* Reference Q.951 Section 5.4.1 for ie */
|
||||
call->connected_number_in_message = 1;
|
||||
call->remote_id.number.valid = 1;
|
||||
call->remote_id.number.presentation =
|
||||
@@ -2278,7 +2376,39 @@ static int receive_connected_number(int full_ie, struct pri *ctrl, q931_call *ca
|
||||
switch (i) {
|
||||
case 0:
|
||||
call->remote_id.number.plan = ie->data[i] & 0x7f;
|
||||
break;
|
||||
|
||||
/*
|
||||
* Work around a bug in a Lucent switch implementation that
|
||||
* sets the extension bit in octet 3 even though octet 3a
|
||||
* is present.
|
||||
*
|
||||
* The same issue was seen in a NI2 switch implementation.
|
||||
* It was probably a Lucent switch configured for NI2
|
||||
* operation. To avoid further surprises, I'm going to
|
||||
* enable the work around for all North American switch
|
||||
* types.
|
||||
*/
|
||||
if (ie->data[i] & 0x80) {
|
||||
/* Octet 3 extension bit is set */
|
||||
if (ctrl->switchtype != PRI_SWITCH_LUCENT5E
|
||||
&& ctrl->switchtype != PRI_SWITCH_ATT4ESS
|
||||
&& ctrl->switchtype != PRI_SWITCH_NI1
|
||||
&& ctrl->switchtype != PRI_SWITCH_NI2
|
||||
&& ctrl->switchtype != PRI_SWITCH_DMS100) {
|
||||
/* Not a potentially buggy switch type. */
|
||||
break;
|
||||
}
|
||||
if (!(ie->data[i + 1] & 0x80)) {
|
||||
/*
|
||||
* The possible octet 3a doesn't have the extension
|
||||
* bit set. It is likely not the erroneous octet 3a.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Octet 3a is present */
|
||||
++i;
|
||||
/* Fall through */
|
||||
case 1:
|
||||
/* Keep only the presentation and screening fields */
|
||||
call->remote_id.number.presentation =
|
||||
@@ -2320,7 +2450,44 @@ static void dump_connected_number(int full_ie, struct pri *ctrl, q931_ie *ie, in
|
||||
prefix, ie2str(full_ie), len, ie->data[0] >> 7,
|
||||
ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07,
|
||||
npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f);
|
||||
break;
|
||||
|
||||
/*
|
||||
* Work around a bug in a Lucent switch implementation that
|
||||
* sets the extension bit in octet 3 even though octet 3a
|
||||
* is present.
|
||||
*
|
||||
* The same issue was seen in a NI2 switch implementation.
|
||||
* It was probably a Lucent switch configured for NI2
|
||||
* operation. To avoid further surprises, I'm going to
|
||||
* enable the work around for all North American switch
|
||||
* types.
|
||||
*/
|
||||
if (ie->data[i] & 0x80) {
|
||||
/* Octet 3 extension bit is set */
|
||||
if (ctrl->switchtype != PRI_SWITCH_LUCENT5E
|
||||
&& ctrl->switchtype != PRI_SWITCH_ATT4ESS
|
||||
&& ctrl->switchtype != PRI_SWITCH_NI1
|
||||
&& ctrl->switchtype != PRI_SWITCH_NI2
|
||||
&& ctrl->switchtype != PRI_SWITCH_DMS100) {
|
||||
/* Not a potentially buggy switch type. */
|
||||
break;
|
||||
}
|
||||
if (!(ie->data[i + 1] & 0x80)) {
|
||||
/*
|
||||
* The possible octet 3a doesn't have the extension
|
||||
* bit set. It is likely not the erroneous octet 3a.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
pri_message(ctrl, "\n");
|
||||
pri_message(ctrl, "%c Switch bug workaround.\n",
|
||||
prefix);
|
||||
pri_message(ctrl, "%c Assuming octet 3a is present.",
|
||||
prefix);
|
||||
}
|
||||
/* Octet 3a is present */
|
||||
++i;
|
||||
/* Fall through */
|
||||
case 1: /* Octet 3a */
|
||||
pri_message(ctrl, "\n");
|
||||
pri_message(ctrl, "%c Ext: %d Presentation: %s (%d)",
|
||||
@@ -2357,6 +2524,7 @@ static int receive_redirecting_number(int full_ie, struct pri *ctrl, q931_call *
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
/* Reference Q.952 Section 4.1.2 for ie */
|
||||
call->redirecting_number_in_message = 1;
|
||||
call->redirecting.from.number.valid = 1;
|
||||
call->redirecting.from.number.presentation =
|
||||
@@ -2435,6 +2603,7 @@ static int receive_redirection_number(int full_ie, struct pri *ctrl, q931_call *
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
/* Reference Q.952 Section 4.1.3 for ie */
|
||||
call->redirection_number.valid = 1;
|
||||
call->redirection_number.presentation =
|
||||
PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
|
||||
@@ -2578,6 +2747,7 @@ static int receive_calling_party_number(int full_ie, struct pri *ctrl, q931_call
|
||||
int i = 0;
|
||||
struct q931_party_number number;
|
||||
|
||||
/* Reference Q.931 Section 4.5.10 for ie */
|
||||
q931_party_number_init(&number);
|
||||
number.valid = 1;
|
||||
number.presentation = PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
|
||||
@@ -2681,10 +2851,33 @@ static void dump_change_status(int full_ie, struct pri *ctrl, q931_ie *ie, int l
|
||||
pri_message(ctrl, " %02x", ie->data[x] & 0x7f);
|
||||
}
|
||||
pri_message(ctrl, " ]\n");
|
||||
|
||||
switch (ctrl->switchtype) {
|
||||
case PRI_SWITCH_NI2:
|
||||
case PRI_SWITCH_DMS100:
|
||||
case PRI_SWITCH_LUCENT5E:
|
||||
case PRI_SWITCH_ATT4ESS:
|
||||
break;
|
||||
default:
|
||||
/* ie not supported by this switch type */
|
||||
pri_message(ctrl, "%c %s is treated as unknown by current switch type.\n",
|
||||
prefix, ie2str(full_ie));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int receive_change_status(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
|
||||
{
|
||||
switch (ctrl->switchtype) {
|
||||
case PRI_SWITCH_NI2:
|
||||
case PRI_SWITCH_DMS100:
|
||||
case PRI_SWITCH_LUCENT5E:
|
||||
case PRI_SWITCH_ATT4ESS:
|
||||
break;
|
||||
default:
|
||||
/* ie not supported by this switch type */
|
||||
return -1;
|
||||
}
|
||||
call->changestatus = ie->data[0] & 0x0f;
|
||||
return 0;
|
||||
}
|
||||
@@ -2807,7 +3000,8 @@ static int receive_progress_indicator(int full_ie, struct pri *ctrl, q931_call *
|
||||
{
|
||||
call->progloc = ie->data[0] & 0xf;
|
||||
call->progcode = (ie->data[0] & 0x60) >> 5;
|
||||
switch (call->progress = (ie->data[1] & 0x7f)) {
|
||||
call->progress = (ie->data[1] & 0x7f);
|
||||
switch (call->progress) {
|
||||
case Q931_PROG_CALL_NOT_E2E_ISDN:
|
||||
call->progressmask |= PRI_PROG_CALL_NOT_E2E_ISDN;
|
||||
break;
|
||||
@@ -2840,7 +3034,7 @@ static int receive_progress_indicator(int full_ie, struct pri *ctrl, q931_call *
|
||||
break;
|
||||
default:
|
||||
pri_error(ctrl, "XXX Invalid Progress indicator value received: %02x\n",(ie->data[1] & 0x7f));
|
||||
break;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -3084,7 +3278,9 @@ static void q931_apdu_msg_expire(struct pri *ctrl, struct q931_call *call, int m
|
||||
|
||||
static int transmit_progress_indicator(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
|
||||
{
|
||||
int code, mask;
|
||||
int code;
|
||||
int mask;
|
||||
|
||||
/* Can't send progress indicator on GR-303 -- EVER! */
|
||||
if (ctrl->link.next && !ctrl->bri)
|
||||
return 0;
|
||||
@@ -3952,8 +4148,11 @@ static int transmit_reverse_charging_indication(int full_ie, struct pri *ctrl, q
|
||||
}
|
||||
|
||||
static struct ie ies[] = {
|
||||
/* Codeset 0 - Comprehension required ie's with varying support. */
|
||||
{ 1, Q931_IE_SEGMENTED_MSG, "Segmented Message" }, /* Not supported. Just ie name is available for message decode. */
|
||||
{ 1, Q931_IE_CHANGE_STATUS, "Change Status Information", dump_change_status, receive_change_status, transmit_change_status },
|
||||
|
||||
/* Codeset 0 - Common */
|
||||
{ 1, NATIONAL_CHANGE_STATUS, "Change Status Information", dump_change_status, receive_change_status, transmit_change_status },
|
||||
{ 0, Q931_LOCKING_SHIFT, "Locking Shift", dump_shift },
|
||||
{ 0, Q931_BEARER_CAPABILITY, "Bearer Capability", dump_bearer_capability, receive_bearer_capability, transmit_bearer_capability },
|
||||
{ 0, Q931_CAUSE, "Cause", dump_cause, receive_cause, transmit_cause },
|
||||
@@ -3985,7 +4184,6 @@ static struct ie ies[] = {
|
||||
{ 1, Q931_IE_FEATURE_ACTIVATE, "Feature Activation" },
|
||||
{ 1, Q931_IE_INFO_REQUEST, "Feature Request" },
|
||||
{ 1, Q931_IE_FEATURE_IND, "Feature Indication" },
|
||||
{ 1, Q931_IE_SEGMENTED_MSG, "Segmented Message" },
|
||||
{ 1, Q931_IE_CALL_IDENTITY, "Call Identity", dump_call_identity },
|
||||
{ 1, Q931_IE_ENDPOINT_ID, "Endpoint Identification" },
|
||||
{ 1, Q931_IE_NOTIFY_IND, "Notification Indicator", dump_notify, receive_notify, transmit_notify },
|
||||
@@ -3997,7 +4195,6 @@ static struct ie ies[] = {
|
||||
{ 1, Q931_IE_USER_USER, "User-User Information", dump_user_user, receive_user_user, transmit_user_user },
|
||||
{ 1, Q931_IE_ESCAPE_FOR_EXT, "Escape for Extension" },
|
||||
{ 1, Q931_IE_CALL_STATUS, "Call Status" },
|
||||
{ 1, Q931_IE_CHANGE_STATUS, "Change Status Information", dump_change_status, receive_change_status, transmit_change_status },
|
||||
{ 1, Q931_IE_CONNECTED_ADDR, "Connected Address", dump_connected_number, receive_connected_number, transmit_connected_number },
|
||||
{ 1, Q931_IE_CONNECTED_NUM, "Connected Number", dump_connected_number, receive_connected_number, transmit_connected_number },
|
||||
{ 1, Q931_IE_CONNECTED_SUBADDR, "Connected Subaddress", dump_connected_subaddr, receive_connected_subaddr, transmit_connected_subaddr },
|
||||
@@ -4789,7 +4986,7 @@ static int add_ie(struct pri *ctrl, q931_call *call, int msgtype, int ie, q931_i
|
||||
}
|
||||
return total_res;
|
||||
} else {
|
||||
pri_error(ctrl, "!! Don't know how to add an IE %s (%d)\n", ie2str(ie), ie);
|
||||
pri_error(ctrl, "!! Don't know how to add IE %d (%s)\n", ie, ie2str(ie));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -5610,11 +5807,12 @@ int q931_notify(struct pri *ctrl, q931_call *c, int channel, int info)
|
||||
return q931_notify_redirection(ctrl, c, info, NULL, NULL);
|
||||
}
|
||||
|
||||
#ifdef ALERTING_NO_PROGRESS
|
||||
static int call_progress_ies[] = { -1 };
|
||||
#else
|
||||
static int call_progress_ies[] = { Q931_PROGRESS_INDICATOR, -1 };
|
||||
static int call_progress_ies[] = {
|
||||
#ifndef ALERTING_NO_PROGRESS
|
||||
Q931_PROGRESS_INDICATOR,
|
||||
#endif
|
||||
-1
|
||||
};
|
||||
|
||||
int q931_call_progress(struct pri *ctrl, q931_call *c, int channel, int info)
|
||||
{
|
||||
@@ -5642,11 +5840,13 @@ int q931_call_progress(struct pri *ctrl, q931_call *c, int channel, int info)
|
||||
return send_message(ctrl, c, Q931_PROGRESS, call_progress_ies);
|
||||
}
|
||||
|
||||
#ifdef ALERTING_NO_PROGRESS
|
||||
static int call_progress_with_cause_ies[] = { Q931_CAUSE, -1 };
|
||||
#else
|
||||
static int call_progress_with_cause_ies[] = { Q931_CAUSE, Q931_PROGRESS_INDICATOR, -1 };
|
||||
static int call_progress_with_cause_ies[] = {
|
||||
Q931_CAUSE,
|
||||
#ifndef ALERTING_NO_PROGRESS
|
||||
Q931_PROGRESS_INDICATOR,
|
||||
#endif
|
||||
-1
|
||||
};
|
||||
|
||||
int q931_call_progress_with_cause(struct pri *ctrl, q931_call *c, int channel, int info, int cause)
|
||||
{
|
||||
@@ -5678,11 +5878,13 @@ int q931_call_progress_with_cause(struct pri *ctrl, q931_call *c, int channel, i
|
||||
return send_message(ctrl, c, Q931_PROGRESS, call_progress_with_cause_ies);
|
||||
}
|
||||
|
||||
#ifdef ALERTING_NO_PROGRESS
|
||||
static int call_proceeding_ies[] = { Q931_CHANNEL_IDENT, -1 };
|
||||
#else
|
||||
static int call_proceeding_ies[] = { Q931_CHANNEL_IDENT, Q931_PROGRESS_INDICATOR, -1 };
|
||||
static int call_proceeding_ies[] = {
|
||||
Q931_CHANNEL_IDENT,
|
||||
#ifndef ALERTING_NO_PROGRESS
|
||||
Q931_PROGRESS_INDICATOR,
|
||||
#endif
|
||||
-1
|
||||
};
|
||||
|
||||
int q931_call_proceeding(struct pri *ctrl, q931_call *c, int channel, int info)
|
||||
{
|
||||
@@ -5713,11 +5915,15 @@ int q931_call_proceeding(struct pri *ctrl, q931_call *c, int channel, int info)
|
||||
c->alive = 1;
|
||||
return send_message(ctrl, c, Q931_CALL_PROCEEDING, call_proceeding_ies);
|
||||
}
|
||||
|
||||
static int alerting_ies[] = {
|
||||
Q931_IE_FACILITY,
|
||||
#ifndef ALERTING_NO_PROGRESS
|
||||
static int alerting_ies[] = { Q931_IE_FACILITY, Q931_PROGRESS_INDICATOR, Q931_IE_USER_USER, -1 };
|
||||
#else
|
||||
static int alerting_ies[] = { Q931_IE_FACILITY, -1 };
|
||||
Q931_PROGRESS_INDICATOR,
|
||||
#endif
|
||||
Q931_IE_USER_USER,
|
||||
-1
|
||||
};
|
||||
|
||||
int q931_alerting(struct pri *ctrl, q931_call *c, int channel, int info)
|
||||
{
|
||||
@@ -5755,9 +5961,14 @@ int q931_alerting(struct pri *ctrl, q931_call *c, int channel, int info)
|
||||
return send_message(ctrl, c, Q931_ALERTING, alerting_ies);
|
||||
}
|
||||
|
||||
static int setup_ack_ies[] = { Q931_CHANNEL_IDENT, Q931_IE_FACILITY, Q931_PROGRESS_INDICATOR, -1 };
|
||||
static int setup_ack_ies[] = {
|
||||
Q931_CHANNEL_IDENT,
|
||||
Q931_IE_FACILITY,
|
||||
Q931_PROGRESS_INDICATOR,
|
||||
-1
|
||||
};
|
||||
|
||||
int q931_setup_ack(struct pri *ctrl, q931_call *c, int channel, int nonisdn)
|
||||
int q931_setup_ack(struct pri *ctrl, q931_call *c, int channel, int nonisdn, int inband)
|
||||
{
|
||||
if (c->ourcallstate == Q931_CALL_STATE_CALL_INDEPENDENT_SERVICE) {
|
||||
/* Cannot send this message when in this state */
|
||||
@@ -5770,12 +5981,20 @@ int q931_setup_ack(struct pri *ctrl, q931_call *c, int channel, int nonisdn)
|
||||
}
|
||||
c->chanflags &= ~FLAG_PREFERRED;
|
||||
c->chanflags |= FLAG_EXCLUSIVE;
|
||||
|
||||
c->progressmask = 0;
|
||||
if (nonisdn && (ctrl->switchtype != PRI_SWITCH_DMS100)) {
|
||||
c->progloc = LOC_PRIV_NET_LOCAL_USER;
|
||||
c->progloc = LOC_PRIV_NET_LOCAL_USER;
|
||||
c->progcode = CODE_CCITT;
|
||||
c->progressmask = PRI_PROG_CALLED_NOT_ISDN;
|
||||
} else
|
||||
c->progressmask = 0;
|
||||
c->progressmask |= PRI_PROG_CALLED_NOT_ISDN;
|
||||
}
|
||||
if (inband) {
|
||||
/* Inband audio is present (i.e. dialtone) */
|
||||
c->progloc = LOC_PRIV_NET_LOCAL_USER;
|
||||
c->progcode = CODE_CCITT;
|
||||
c->progressmask |= PRI_PROG_INBAND_AVAILABLE;
|
||||
}
|
||||
|
||||
UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_OVERLAP_RECEIVING);
|
||||
c->peercallstate = Q931_CALL_STATE_OVERLAP_SENDING;
|
||||
c->alive = 1;
|
||||
@@ -5876,7 +6095,7 @@ int q931_connect(struct pri *ctrl, q931_call *c, int channel, int nonisdn)
|
||||
c->chanflags &= ~FLAG_PREFERRED;
|
||||
c->chanflags |= FLAG_EXCLUSIVE;
|
||||
if (nonisdn && (ctrl->switchtype != PRI_SWITCH_DMS100)) {
|
||||
c->progloc = LOC_PRIV_NET_LOCAL_USER;
|
||||
c->progloc = LOC_PRIV_NET_LOCAL_USER;
|
||||
c->progcode = CODE_CCITT;
|
||||
c->progressmask = PRI_PROG_CALLED_NOT_ISDN;
|
||||
} else
|
||||
@@ -6267,6 +6486,9 @@ int q931_setup(struct pri *ctrl, q931_call *c, struct pri_sr *req)
|
||||
c->chanflags = FLAG_PREFERRED;
|
||||
}
|
||||
}
|
||||
if (ctrl->localtype == PRI_CPE) {
|
||||
c->channel_id_ie_mandatory = 1;
|
||||
}
|
||||
|
||||
c->slotmap = -1;
|
||||
c->nonisdn = req->nonisdn;
|
||||
@@ -7243,6 +7465,7 @@ static int prepare_to_handle_q931_message(struct pri *ctrl, q931_mh *mh, q931_ca
|
||||
c->useruserinfo[0] = '\0';
|
||||
c->cause = -1;
|
||||
/* Fall through */
|
||||
case Q931_SETUP_ACKNOWLEDGE:
|
||||
case Q931_CALL_PROCEEDING:
|
||||
c->progress = -1;
|
||||
c->progressmask = 0;
|
||||
@@ -7256,6 +7479,8 @@ static int prepare_to_handle_q931_message(struct pri *ctrl, q931_mh *mh, q931_ca
|
||||
c->cause = -1;
|
||||
c->causecode = -1;
|
||||
c->causeloc = -1;
|
||||
c->progress = -1;
|
||||
c->progressmask = 0;
|
||||
c->aoc_units = -1;
|
||||
pri_schedule_del(ctrl, c->retranstimer);
|
||||
c->retranstimer = 0;
|
||||
@@ -7289,8 +7514,6 @@ static int prepare_to_handle_q931_message(struct pri *ctrl, q931_mh *mh, q931_ca
|
||||
break;
|
||||
case Q931_STATUS_ENQUIRY:
|
||||
break;
|
||||
case Q931_SETUP_ACKNOWLEDGE:
|
||||
break;
|
||||
case Q931_NOTIFY:
|
||||
c->notify = -1;
|
||||
q931_party_number_init(&c->redirection_number);
|
||||
@@ -7462,12 +7685,13 @@ int q931_receive(struct q921_link *link, q931_h *h, int len)
|
||||
int res;
|
||||
int r;
|
||||
int mandies[MAX_MAND_IES];
|
||||
int missingmand;
|
||||
int is_mandatory;
|
||||
int codeset, cur_codeset;
|
||||
int last_ie[8];
|
||||
int cref;
|
||||
int allow_event;
|
||||
int allow_posthandle;
|
||||
enum mandatory_ie_status mand_status;
|
||||
|
||||
ctrl = link->ctrl;
|
||||
memset(last_ie, 0, sizeof(last_ie));
|
||||
@@ -7547,7 +7771,7 @@ int q931_receive(struct q921_link *link, q931_h *h, int len)
|
||||
q931_clr_subcommands(ctrl);
|
||||
q931_display_clear(c);
|
||||
|
||||
/* Handle IEs */
|
||||
/* Determine which ies are mandatory for this message. */
|
||||
memset(mandies, 0, sizeof(mandies));
|
||||
for (x = 0; x < ARRAY_LEN(msgs); ++x) {
|
||||
if (msgs[x].msgnum == mh->msg) {
|
||||
@@ -7555,6 +7779,25 @@ int q931_receive(struct q921_link *link, q931_h *h, int len)
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (x = 0; x < ARRAY_LEN(mandies); ++x) {
|
||||
if (mandies[x]) {
|
||||
/* Check mandatory channel identification ie exceptions */
|
||||
if (mandies[x] != Q931_CHANNEL_IDENT
|
||||
/* Always mandatory for RESUME_ACKNOWLEDGE */
|
||||
|| mh->msg == Q931_RESUME_ACKNOWLEDGE
|
||||
/* Mandatory in Net -> CPE direction for SETUP */
|
||||
|| (mh->msg == Q931_SETUP && ctrl->localtype == PRI_CPE)
|
||||
/* Mandatory for first SETUP response message in Net -> CPE direction. */
|
||||
|| c->channel_id_ie_mandatory) {
|
||||
/* ie is mandatory for this message */
|
||||
continue;
|
||||
}
|
||||
/* ie is not mandatory for this message */
|
||||
mandies[x] = 0;
|
||||
}
|
||||
}
|
||||
mand_status = MAND_STATUS_OK;
|
||||
|
||||
/* Do real IE processing */
|
||||
len -= (h->crlen + 3);
|
||||
codeset = cur_codeset = 0;
|
||||
@@ -7571,10 +7814,16 @@ int q931_receive(struct q921_link *link, q931_h *h, int len)
|
||||
q931_display_clear(c);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check if processing a mandatory ie. */
|
||||
is_mandatory = 0;
|
||||
for (y = 0; y < ARRAY_LEN(mandies); ++y) {
|
||||
if (mandies[y] == Q931_FULL_IE(cur_codeset, ie->ie))
|
||||
if (mandies[y] == Q931_FULL_IE(cur_codeset, ie->ie)) {
|
||||
mandies[y] = 0;
|
||||
is_mandatory = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Special processing for codeset shifts */
|
||||
switch (ie->ie & 0xf8) {
|
||||
case Q931_LOCKING_SHIFT:
|
||||
@@ -7617,6 +7866,15 @@ int q931_receive(struct q921_link *link, q931_h *h, int len)
|
||||
/* Fall through */
|
||||
default:
|
||||
y = q931_handle_ie(cur_codeset, ctrl, c, mh->msg, ie);
|
||||
if (y < 0 && is_mandatory) {
|
||||
/* Error processing mandatory ie. */
|
||||
mand_status = MAND_STATUS_CONTENT_ERROR;
|
||||
pri_error(ctrl, "%s: Error in mandatory IE %d (cs%d, %s)\n",
|
||||
msg2str(mh->msg),
|
||||
ie->ie,
|
||||
cur_codeset,
|
||||
ie2str(Q931_FULL_IE(codeset, ie->ie)));
|
||||
}
|
||||
/* XXX Applicable to codeset 0 only? XXX */
|
||||
if (!cur_codeset && !(ie->ie & 0xf0) && (y < 0)) {
|
||||
/*
|
||||
@@ -7633,19 +7891,21 @@ int q931_receive(struct q921_link *link, q931_h *h, int len)
|
||||
break;
|
||||
}
|
||||
}
|
||||
missingmand = 0;
|
||||
|
||||
/* Check for missing mandatory ies. */
|
||||
for (x = 0; x < ARRAY_LEN(mandies); ++x) {
|
||||
if (mandies[x]) {
|
||||
/* check if there is no channel identification when we're configured as network -> that's not an error */
|
||||
if (((ctrl->localtype != PRI_NETWORK) || (mh->msg != Q931_SETUP) || (mandies[x] != Q931_CHANNEL_IDENT)) &&
|
||||
((mh->msg != Q931_PROGRESS) || (mandies[x] != Q931_PROGRESS_INDICATOR))) {
|
||||
pri_error(ctrl, "XXX Missing handling for mandatory IE %d (cs%d, %s) XXX\n", Q931_IE_IE(mandies[x]), Q931_IE_CODESET(mandies[x]), ie2str(mandies[x]));
|
||||
missingmand++;
|
||||
}
|
||||
/* This mandatory ie was not processed. */
|
||||
mand_status = MAND_STATUS_MISSING;
|
||||
pri_error(ctrl, "%s: Missing mandatory IE %d (cs%d, %s)\n",
|
||||
msg2str(mh->msg),
|
||||
Q931_IE_IE(mandies[x]),
|
||||
Q931_IE_CODESET(mandies[x]),
|
||||
ie2str(mandies[x]));
|
||||
}
|
||||
}
|
||||
|
||||
if (!missingmand) {
|
||||
if (mand_status == MAND_STATUS_OK) {
|
||||
switch (mh->msg) {
|
||||
case Q931_SETUP:
|
||||
case Q931_CONNECT:
|
||||
@@ -7681,7 +7941,7 @@ int q931_receive(struct q921_link *link, q931_h *h, int len)
|
||||
}
|
||||
|
||||
if (allow_posthandle) {
|
||||
res = post_handle_q931_message(ctrl, mh, c, missingmand);
|
||||
res = post_handle_q931_message(ctrl, mh, c, mand_status);
|
||||
if (res == Q931_RES_HAVEEVENT && !allow_event) {
|
||||
res = 0;
|
||||
}
|
||||
@@ -8551,7 +8811,7 @@ static void q931_restart_notify(struct q931_call *call)
|
||||
* \param ctrl D channel controller.
|
||||
* \param mh Q.931 message header.
|
||||
* \param c Q.931 call leg.
|
||||
* \param missingmand Number of missing mandatory ie's.
|
||||
* \param mand_status Mandatory ie status
|
||||
*
|
||||
* \note
|
||||
* When this function returns c may be destroyed so you can no
|
||||
@@ -8561,19 +8821,33 @@ static void q931_restart_notify(struct q931_call *call)
|
||||
* \retval Q931_RES_HAVEEVENT if have an event.
|
||||
* \retval -1 on error.
|
||||
*/
|
||||
static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct q931_call *c, int missingmand)
|
||||
static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct q931_call *c, enum mandatory_ie_status mand_status)
|
||||
{
|
||||
int res;
|
||||
int changed;
|
||||
int mand_cause;
|
||||
enum Q931_CALL_STATE ourcallstate_orig;
|
||||
struct apdu_event *cur = NULL;
|
||||
struct pri_subcommand *subcmd;
|
||||
struct q931_call *master_call;
|
||||
|
||||
mand_cause = 0;
|
||||
switch (mand_status) {
|
||||
case MAND_STATUS_OK:
|
||||
break;
|
||||
case MAND_STATUS_CONTENT_ERROR:
|
||||
mand_cause = PRI_CAUSE_INVALID_IE_CONTENTS;
|
||||
break;
|
||||
case MAND_STATUS_MISSING:
|
||||
mand_cause = PRI_CAUSE_MANDATORY_IE_MISSING;
|
||||
break;
|
||||
}
|
||||
|
||||
switch(mh->msg) {
|
||||
case Q931_RESTART:
|
||||
q931_display_subcmd(ctrl, c);
|
||||
if (missingmand) {
|
||||
q931_status(ctrl, c, PRI_CAUSE_MANDATORY_IE_MISSING);
|
||||
if (mand_status != MAND_STATUS_OK) {
|
||||
q931_status(ctrl, c, mand_cause);
|
||||
pri_destroycall(ctrl, c);
|
||||
break;
|
||||
}
|
||||
@@ -8631,9 +8905,8 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
return Q931_RES_HAVEEVENT;
|
||||
case Q931_SETUP:
|
||||
q931_display_subcmd(ctrl, c);
|
||||
|
||||
if (missingmand) {
|
||||
q931_release_complete(ctrl, c, PRI_CAUSE_MANDATORY_IE_MISSING);
|
||||
if (mand_status != MAND_STATUS_OK) {
|
||||
q931_release_complete(ctrl, c, mand_cause);
|
||||
break;
|
||||
}
|
||||
/* Must be new call */
|
||||
@@ -8676,11 +8949,24 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
return Q931_RES_HAVEEVENT;
|
||||
case Q931_ALERTING:
|
||||
q931_display_subcmd(ctrl, c);
|
||||
if (mand_status != MAND_STATUS_OK) {
|
||||
q931_status(ctrl, c, mand_cause);
|
||||
break;
|
||||
}
|
||||
stop_t303(c->master_call);
|
||||
if (c->newcall) {
|
||||
q931_release_complete(ctrl, c, newcall_rel_comp_cause(c));
|
||||
break;
|
||||
}
|
||||
switch (c->ourcallstate) {
|
||||
default:
|
||||
q931_status(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE);
|
||||
return 0;
|
||||
case Q931_CALL_STATE_CALL_INITIATED:
|
||||
case Q931_CALL_STATE_OVERLAP_SENDING:
|
||||
case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING:
|
||||
break;
|
||||
}
|
||||
UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_CALL_DELIVERED);
|
||||
c->peercallstate = Q931_CALL_STATE_CALL_RECEIVED;
|
||||
ctrl->ev.e = PRI_EVENT_RINGING;
|
||||
@@ -8712,6 +8998,10 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
return Q931_RES_HAVEEVENT;
|
||||
case Q931_CONNECT:
|
||||
q931_display_subcmd(ctrl, c);
|
||||
if (mand_status != MAND_STATUS_OK) {
|
||||
q931_status(ctrl, c, mand_cause);
|
||||
break;
|
||||
}
|
||||
stop_t303(c->master_call);
|
||||
if (c->newcall) {
|
||||
q931_release_complete(ctrl, c, newcall_rel_comp_cause(c));
|
||||
@@ -8790,16 +9080,15 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
}
|
||||
break;
|
||||
case Q931_PROGRESS:
|
||||
if (missingmand) {
|
||||
q931_status(ctrl, c, PRI_CAUSE_MANDATORY_IE_MISSING);
|
||||
pri_destroycall(ctrl, c);
|
||||
break;
|
||||
}
|
||||
ctrl->ev.e = PRI_EVENT_PROGRESS;
|
||||
ctrl->ev.proceeding.cause = c->cause;
|
||||
/* Fall through */
|
||||
case Q931_CALL_PROCEEDING:
|
||||
q931_display_subcmd(ctrl, c);
|
||||
if (mand_status != MAND_STATUS_OK) {
|
||||
q931_status(ctrl, c, mand_cause);
|
||||
break;
|
||||
}
|
||||
stop_t303(c->master_call);
|
||||
ctrl->ev.proceeding.subcmds = &ctrl->subcmds;
|
||||
if (c->newcall) {
|
||||
@@ -8851,11 +9140,8 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
}
|
||||
switch (c->ourcallstate) {
|
||||
default:
|
||||
if (ctrl->localtype == PRI_NETWORK || ctrl->switchtype == PRI_SWITCH_QSIG) {
|
||||
q931_status(ctrl, c, PRI_CAUSE_WRONG_MESSAGE);
|
||||
break;
|
||||
}
|
||||
/* Fall through */
|
||||
q931_status(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE);
|
||||
return 0;
|
||||
case Q931_CALL_STATE_CONNECT_REQUEST:
|
||||
case Q931_CALL_STATE_ACTIVE:
|
||||
UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_ACTIVE);
|
||||
@@ -8872,9 +9158,8 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
break;
|
||||
case Q931_STATUS:
|
||||
q931_display_subcmd(ctrl, c);
|
||||
if (missingmand) {
|
||||
q931_status(ctrl, c, PRI_CAUSE_MANDATORY_IE_MISSING);
|
||||
pri_destroycall(ctrl, c);
|
||||
if (mand_status != MAND_STATUS_OK) {
|
||||
q931_status(ctrl, c, mand_cause);
|
||||
break;
|
||||
}
|
||||
if (c->newcall) {
|
||||
@@ -8980,9 +9265,9 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
case Q931_RELEASE:
|
||||
q931_display_subcmd(ctrl, c);
|
||||
c->hangupinitiated = 1;
|
||||
if (missingmand) {
|
||||
/* Force cause to be mandatory IE missing */
|
||||
c->cause = PRI_CAUSE_MANDATORY_IE_MISSING;
|
||||
if (mand_status != MAND_STATUS_OK) {
|
||||
/* Force mandatory ie cause */
|
||||
c->cause = mand_cause;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -9026,9 +9311,9 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
case Q931_DISCONNECT:
|
||||
q931_display_subcmd(ctrl, c);
|
||||
c->hangupinitiated = 1;
|
||||
if (missingmand) {
|
||||
if (mand_status != MAND_STATUS_OK) {
|
||||
/* Still let user call release */
|
||||
c->cause = PRI_CAUSE_MANDATORY_IE_MISSING;
|
||||
c->cause = mand_cause;
|
||||
}
|
||||
if (c->newcall) {
|
||||
q931_release_complete(ctrl, c, newcall_rel_comp_cause(c));
|
||||
@@ -9081,14 +9366,46 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
}
|
||||
}
|
||||
|
||||
ourcallstate_orig = c->ourcallstate;
|
||||
UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_DISCONNECT_INDICATION);
|
||||
c->peercallstate = Q931_CALL_STATE_DISCONNECT_REQUEST;
|
||||
c->sendhangupack = 1;
|
||||
|
||||
/* wait for a RELEASE so that sufficient time has passed
|
||||
for the inband audio to be heard */
|
||||
if (ctrl->acceptinbanddisconnect && (c->progressmask & PRI_PROG_INBAND_AVAILABLE))
|
||||
if (ctrl->acceptinbanddisconnect
|
||||
&& (c->progressmask & PRI_PROG_INBAND_AVAILABLE)) {
|
||||
switch (ourcallstate_orig) {
|
||||
case Q931_CALL_STATE_CALL_INITIATED:
|
||||
case Q931_CALL_STATE_OVERLAP_SENDING:
|
||||
case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING:
|
||||
case Q931_CALL_STATE_CALL_DELIVERED:
|
||||
/*
|
||||
* Open the media path if it isn't already open so
|
||||
* the user can hear the inband audio.
|
||||
*/
|
||||
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
|
||||
pri_message(ctrl, "Report the DISCONNECT as a PROGRESS instead.\n");
|
||||
}
|
||||
ctrl->ev.e = PRI_EVENT_PROGRESS;
|
||||
ctrl->ev.proceeding.cause = c->cause;
|
||||
ctrl->ev.proceeding.subcmds = &ctrl->subcmds;
|
||||
ctrl->ev.proceeding.channel = q931_encode_channel(c);
|
||||
ctrl->ev.proceeding.progress = c->progress;
|
||||
ctrl->ev.proceeding.progressmask = c->progressmask;
|
||||
ctrl->ev.proceeding.cref = c->cr;
|
||||
ctrl->ev.proceeding.call = c->master_call;
|
||||
return Q931_RES_HAVEEVENT;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Suppress reporting DISCONNECT to the upper layer. The
|
||||
* media path should already be open and we cannot report
|
||||
* a PROGRESS at this time anyway.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
/* Return such an event */
|
||||
ctrl->ev.e = PRI_EVENT_HANGUP_REQ;
|
||||
@@ -9155,7 +9472,7 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
q931_release_complete(ctrl, c, newcall_rel_comp_cause(c));
|
||||
break;
|
||||
}
|
||||
if (c->ourcallstate != Q931_CALL_STATE_OVERLAP_RECEIVING) {
|
||||
if (strlen(c->keypad_digits)) {
|
||||
ctrl->ev.e = PRI_EVENT_KEYPAD_DIGIT;
|
||||
ctrl->ev.digit.subcmds = &ctrl->subcmds;
|
||||
ctrl->ev.digit.call = c->master_call;
|
||||
@@ -9188,17 +9505,29 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
break;
|
||||
case Q931_SETUP_ACKNOWLEDGE:
|
||||
q931_display_subcmd(ctrl, c);
|
||||
if (mand_status != MAND_STATUS_OK) {
|
||||
q931_status(ctrl, c, mand_cause);
|
||||
break;
|
||||
}
|
||||
stop_t303(c->master_call);
|
||||
if (c->newcall) {
|
||||
q931_release_complete(ctrl, c, newcall_rel_comp_cause(c));
|
||||
break;
|
||||
}
|
||||
switch (c->ourcallstate) {
|
||||
default:
|
||||
q931_status(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE);
|
||||
return 0;
|
||||
case Q931_CALL_STATE_CALL_INITIATED:
|
||||
break;
|
||||
}
|
||||
UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_OVERLAP_SENDING);
|
||||
c->peercallstate = Q931_CALL_STATE_OVERLAP_RECEIVING;
|
||||
ctrl->ev.e = PRI_EVENT_SETUP_ACK;
|
||||
ctrl->ev.setup_ack.subcmds = &ctrl->subcmds;
|
||||
ctrl->ev.setup_ack.channel = q931_encode_channel(c);
|
||||
ctrl->ev.setup_ack.call = c->master_call;
|
||||
ctrl->ev.setup_ack.progressmask = c->progressmask;
|
||||
|
||||
for (cur = c->apdus; cur; cur = cur->next) {
|
||||
if (!cur->sent && cur->message == Q931_FACILITY) {
|
||||
@@ -9405,9 +9734,9 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
master_call = c->master_call;
|
||||
switch (master_call->hold_state) {
|
||||
case Q931_HOLD_STATE_HOLD_REQ:
|
||||
if (missingmand) {
|
||||
if (mand_status != MAND_STATUS_OK) {
|
||||
/* Still, let hold rejection continue. */
|
||||
c->cause = PRI_CAUSE_MANDATORY_IE_MISSING;
|
||||
c->cause = mand_cause;
|
||||
}
|
||||
ctrl->ev.e = PRI_EVENT_HOLD_REJ;
|
||||
ctrl->ev.hold_rej.channel = q931_encode_channel(c);
|
||||
@@ -9529,9 +9858,9 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
pri_schedule_del(ctrl, master_call->hold_timer);
|
||||
master_call->hold_timer = 0;
|
||||
|
||||
if (missingmand) {
|
||||
if (mand_status != MAND_STATUS_OK) {
|
||||
/* Still, let retrive rejection continue. */
|
||||
c->cause = PRI_CAUSE_MANDATORY_IE_MISSING;
|
||||
c->cause = mand_cause;
|
||||
}
|
||||
ctrl->ev.e = PRI_EVENT_RETRIEVE_REJ;
|
||||
ctrl->ev.retrieve_rej.channel = q931_encode_channel(c);
|
||||
|
||||
Reference in New Issue
Block a user