Description
Issue type:
Bug
Description:
A B-Channel can remain blocked (marked as not idle) in BRI Net point-to-multipoint configuration, if following conditions occur:
- Call established,
- Loss of BRI link (disconnection),
- Hangup initiated before layer 2 release indication.
Operating System detail:
(problem not related to OS)
libpri version:
1.6.0 (should also occur with 1.6.1: involved code unchanged)
Information on any third party software:
Asterisk 18.6.0, dahdi 3.1.0
Frequency and timing of the issue:
Always, in conditions described below (see: steps to reproduce the issue)
Symptoms described in specific detail:
Asterisk does not use the B-Channel anymore for outgoing calls.
Steps required to reproduce the issue:
When a call is established, using libpri and Asterisk, on a BRI span configured in Net point-to-multipoint mode,
if the BRI link is lost (disconnection),
if Asterisk user hangs up quickly (before BRI layer 2 down indication)
then the B Channel never goes back Idle, even after link reconnection.
Workarounds in detail with specific steps:
Restart Asterisk chan_dahdi.so module (module unload / module load, dahdi restart should work too).
Debugging output:
When the problem occurs, Asterisk "pri show channels" shows B-Channels as not Idle, with no Asterisk Channel associated.
Example, with 2 B-Channels blocked :
# rasterisk -x 'pri show channels'
PRI B Chan Call PRI Channel
Span Chan Chan Idle Level Call Name
1 1 Yes No Idle No
2 2 Yes No Idle No
3 3 Yes Yes Idle No
4 4 Yes Yes Idle No
Analysis:
The problem comes from libpri q931_dl_event() function ("Receive a DL event from layer 2"), when processing Q931_DL_EVENT_DL_RELEASE_IND after an disconnect request, specifically in Net point-to-multipoint configuration (bri_net_ptmp) :
- q931_dl_event() processes Q931_DL_EVENT_DL_RELEASE_IND,
- call state (call->ourcallstate) is Q931_CALL_STATE_DISCONNECT_REQUEST,
- q931_dl_event() "switch (call->ourcallstate)" executes default section,
- link outboundbroadcast flag (cur->outboundbroadcast) is true,
- a comment says "Simply destroy non-winning subcalls." but code actually does not check "winning" status of subcall, and calls q931_destroycall().
If we fix the test, in accordance with the comment :
replace: if (cur->outboundbroadcast)
with: if (cur->outboundbroadcast && call != q931_find_winning_call(call))
then the B-Channel blocking problem does not occur any more.
I will try to submit a patch (first time for me in new Issue / Code Contribution environment).