]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
When a call going out an NT-PTMP port gets rejected, Asterisk crashes.
authorRichard Mudgett <rmudgett@digium.com>
Fri, 1 Apr 2011 23:15:42 +0000 (23:15 +0000)
committerRichard Mudgett <rmudgett@digium.com>
Fri, 1 Apr 2011 23:15:42 +0000 (23:15 +0000)
If a call is sent to an ISDN phone that rejects the call with
RELEASE_COMPLETE(cause: call reject(21), or busy(17)) Asterisk crashes.

I could not get my setup to crash.  However, I could see the possibility
from a race condition between queuing an AST_CONTROL_BUSY to the core and
then queueing an AST_CONTROL_HANGUP.  If the AST_CONTROL_BUSY is processed
before the AST_CONTROL_HANGUP is queued, the ast_channel could be
destroyed out from under chan_misdn.

Avoid this particular crash scenario by not queueing the
AST_CONTROL_HANGUP if the AST_CONTROL_BUSY was queued.

(closes issue #18408)
Reported by: wimpy
Patches:
      issue18408_v1.8.patch uploaded by rmudgett (license 664)
Tested by: rmudgett, wimpy

JIRA SWP-2679

git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.8@312509 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_misdn.c

index eb6e9bd5dae4c0f6ddd45d5a813fe3184eb68df2..76e6eb8d9cce89d063f96848f93083085a0ec2d9 100644 (file)
@@ -679,7 +679,7 @@ static ast_mutex_t cl_te_lock;
 static enum event_response_e
 cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data);
 
-static void send_cause2ast(struct ast_channel *ast, struct misdn_bchannel*bc, struct chan_list *ch);
+static int send_cause2ast(struct ast_channel *ast, struct misdn_bchannel *bc, struct chan_list *ch);
 
 static void cl_queue_chan(struct chan_list *chan);
 
@@ -8365,8 +8365,7 @@ static void hangup_chan(struct chan_list *ch, struct misdn_bchannel *bc)
                cb_log(2, port, " --> hangup\n");
                ch->need_hangup = 0;
                ch->need_queue_hangup = 0;
-               if (ch->ast) {
-                       send_cause2ast(ch->ast, bc, ch);
+               if (ch->ast && send_cause2ast(ch->ast, bc, ch)) {
                        ast_hangup(ch->ast);
                }
                return;
@@ -8374,13 +8373,15 @@ static void hangup_chan(struct chan_list *ch, struct misdn_bchannel *bc)
 
        if (!ch->need_queue_hangup) {
                cb_log(2, port, " --> No need to queue hangup\n");
+               return;
        }
 
        ch->need_queue_hangup = 0;
        if (ch->ast) {
-               send_cause2ast(ch->ast, bc, ch);
-               ast_queue_hangup_with_cause(ch->ast, bc->cause);
-               cb_log(2, port, " --> queue_hangup\n");
+               if (send_cause2ast(ch->ast, bc, ch)) {
+                       ast_queue_hangup_with_cause(ch->ast, bc->cause);
+                       cb_log(2, port, " --> queue_hangup\n");
+               }
        } else {
                cb_log(1, port, "Cannot hangup chan, no ast\n");
        }
@@ -8654,26 +8655,31 @@ static void do_immediate_setup(struct misdn_bchannel *bc, struct chan_list *ch,
        }
 }
 
+/*!
+ * \retval -1 if can hangup after calling.
+ * \retval 0 if cannot hangup after calling.
+ */
+static int send_cause2ast(struct ast_channel *ast, struct misdn_bchannel *bc, struct chan_list *ch)
+{
+       int can_hangup;
 
-
-static void send_cause2ast(struct ast_channel *ast, struct misdn_bchannel *bc, struct chan_list *ch) {
        if (!ast) {
                chan_misdn_log(1, 0, "send_cause2ast: No Ast\n");
-               return;
+               return 0;
        }
        if (!bc) {
                chan_misdn_log(1, 0, "send_cause2ast: No BC\n");
-               return;
+               return 0;
        }
        if (!ch) {
                chan_misdn_log(1, 0, "send_cause2ast: No Ch\n");
-               return;
+               return 0;
        }
 
        ast->hangupcause = bc->cause;
 
+       can_hangup = -1;
        switch (bc->cause) {
-
        case AST_CAUSE_UNALLOCATED:
        case AST_CAUSE_NO_ROUTE_TRANSIT_NET:
        case AST_CAUSE_NO_ROUTE_DESTINATION:
@@ -8700,15 +8706,16 @@ static void send_cause2ast(struct ast_channel *ast, struct misdn_bchannel *bc, s
                        chan_misdn_log(1, bc ? bc->port : 0, "Queued busy already\n");
                        break;
                }
+               ch->need_busy = 0;
 
                chan_misdn_log(1, bc ? bc->port : 0, " --> * SEND: Queue Busy pid:%d\n", bc ? bc->pid : -1);
-
                ast_queue_control(ast, AST_CONTROL_BUSY);
 
-               ch->need_busy = 0;
-
+               /* The BUSY is likely to cause a hangup or the user needs to hear it. */
+               can_hangup = 0;
                break;
        }
+       return can_hangup;
 }