[libpri-commits] rmudgett: branch 1.4 r2337 - in /branches/1.4: pri_internal.h q931.c
SVN commits to the libpri project
libpri-commits at lists.digium.com
Wed Feb 17 14:21:23 CST 2016
Author: rmudgett
Date: Wed Feb 17 14:21:18 2016
New Revision: 2337
URL: http://svnview.digium.com/svn/libpri?view=rev&rev=2337
Log:
q931.c: Tighten mandatory ie checks.
Libpri was lax in checking if a missing channel identification ie is
mandatory for the SETUP ACKNOWLEDGE, PROCEEDING, ALERTING, and CONNECT
messages. That ie is mandatory when those messages are the first response
to a SETUP message sent by the CPE side.
* Made those messages check if a missing channel identification ie is
mandatory and send a STATUS with cause 96 "Mandatory information element
is missing" in response.
Libpri did not care if a mandatory ie had a coding error.
* Made coding errors in mandatory ie's send a STATUS with cause 100
"Invalid information element contents" in response.
* Fixed detection of coding errors in channel identification ie.
SWP-8721
SWP-8722
Modified:
branches/1.4/pri_internal.h
branches/1.4/q931.c
Modified: branches/1.4/pri_internal.h
URL: http://svnview.digium.com/svn/libpri/branches/1.4/pri_internal.h?view=diff&rev=2337&r1=2336&r2=2337
==============================================================================
--- branches/1.4/pri_internal.h (original)
+++ branches/1.4/pri_internal.h Wed Feb 17 14:21:18 2016
@@ -647,10 +647,13 @@
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 {
Modified: branches/1.4/q931.c
URL: http://svnview.digium.com/svn/libpri/branches/1.4/q931.c?view=diff&rev=2337&r1=2336&r2=2337
==============================================================================
--- branches/1.4/q931.c (original)
+++ branches/1.4/q931.c Wed Feb 17 14:21:18 2016
@@ -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 @@
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 @@
{ 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 @@
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 @@
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 @@
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 @@
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 @@
}
}
} 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 @@
}
}
}
+ } 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 @@
(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 @@
++pos;
}
if (pos < len) {
+ /* One or more 3.3 octets present */
if (!(ie->data[pos - 1] & 0x10)) {
/* Number specified */
do {
@@ -2864,7 +2936,7 @@
break;
default:
pri_error(ctrl, "XXX Invalid Progress indicator value received: %02x\n",(ie->data[1] & 0x7f));
- break;
+ return -1;
}
return 0;
}
@@ -6316,6 +6388,9 @@
c->chanflags = FLAG_PREFERRED;
}
}
+ if (ctrl->localtype == PRI_CPE) {
+ c->channel_id_ie_mandatory = 1;
+ }
c->slotmap = -1;
c->nonisdn = req->nonisdn;
@@ -7510,12 +7585,13 @@
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));
@@ -7595,7 +7671,7 @@
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) {
@@ -7603,6 +7679,25 @@
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;
@@ -7619,10 +7714,16 @@
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:
@@ -7665,6 +7766,15 @@
/* 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)) {
/*
@@ -7681,19 +7791,21 @@
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++;
- }
- }
- }
-
- if (!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 (mand_status == MAND_STATUS_OK) {
switch (mh->msg) {
case Q931_SETUP:
case Q931_CONNECT:
@@ -7729,7 +7841,7 @@
}
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;
}
@@ -8599,7 +8711,7 @@
* \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
@@ -8609,19 +8721,32 @@
* \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;
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;
}
@@ -8679,9 +8804,8 @@
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 */
@@ -8724,6 +8848,10 @@
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));
@@ -8769,6 +8897,10 @@
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));
@@ -8847,16 +8979,15 @@
}
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) {
@@ -8926,9 +9057,8 @@
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) {
@@ -9034,9 +9164,9 @@
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;
}
/*
@@ -9080,9 +9210,9 @@
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));
@@ -9242,6 +9372,10 @@
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));
@@ -9467,9 +9601,9 @@
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);
@@ -9591,9 +9725,9 @@
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);
More information about the libpri-commits
mailing list