]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
openr2(5/6): added cli command -- mfcr2 destroy link <index>
authorTzafrir Cohen <tzafrir.cohen@xorcom.com>
Mon, 22 Apr 2019 19:14:32 +0000 (22:14 +0300)
committerOron Peled <oron.peled@xorcom.com>
Mon, 22 Jul 2019 18:11:12 +0000 (21:11 +0300)
Change-Id: I452d6a853bcd8c6e194455b19e5e017713e9c0fe
Signed-off-by: Oron Peled <oron.peled@xorcom.com>
channels/chan_dahdi.c

index 1a78947bc800aacab8ec43632897b5ecf48ef4c3..261604d7f162892fbce61e9be89e078cb38b5555 100644 (file)
@@ -749,6 +749,7 @@ struct dahdi_mfcr2 {
        openr2_context_t *protocol_context;    /*!< OpenR2 context handle */
        struct dahdi_pvt *pvts[SIG_MFCR2_MAX_CHANNELS];     /*!< Member channel pvt structs */
        int numchans;                          /*!< Number of channels in this R2 block */
+       int live_chans;                        /*!< Number of unremoved channels in this R2 block */
        int nodev;                             /*!< Link disconnected? */
        struct dahdi_mfcr2_conf conf;          /*!< Configuration used to setup this pseudo-link */
 };
@@ -758,6 +759,8 @@ struct r2link_entry {
        AST_LIST_ENTRY(r2link_entry) list;
 };
 static AST_LIST_HEAD_STATIC(r2links, r2link_entry);
+static struct r2links nodev_r2links = AST_LIST_HEAD_INIT_VALUE;
+
 
 /* how many r2links have been malloc'd */
 static int r2links_count = 0;
@@ -3548,6 +3551,21 @@ static void handle_clear_alarms(struct dahdi_pvt *p)
 }
 
 #ifdef HAVE_OPENR2
+static void mfcr2_queue_for_destruction(const struct dahdi_pvt *p)
+{
+       const struct dahdi_mfcr2 *r2link = p->mfcr2;
+       struct r2link_entry *cur;
+       AST_LIST_LOCK(&r2links);
+       AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links, cur, list) {
+               if (r2link == &cur->mfcr2) {
+                       ast_debug(3, "MFC/R2 channel %d queued for destruction\n", p->channel);
+                       AST_LIST_MOVE_CURRENT(&nodev_r2links, list);
+                       break;
+               }
+       }
+       AST_LIST_TRAVERSE_SAFE_END;
+       AST_LIST_UNLOCK(&r2links);
+}
 
 static int dahdi_r2_answer(struct dahdi_pvt *p)
 {
@@ -3633,6 +3651,9 @@ static void dahdi_r2_on_hardware_alarm(openr2_chan_t *r2chan, int alarm)
        p->inalarm = alarm ? 1 : 0;
        if (p->inalarm) {
                res = get_alarms(p);
+               if (res == DAHDI_ALARM_NOTOPEN) {
+                       mfcr2_queue_for_destruction(p);
+               }
                handle_alarms(p, res);
        } else {
                handle_clear_alarms(p);
@@ -5490,6 +5511,49 @@ static void dahdi_unlink_ss7_pvt(struct dahdi_pvt *pvt)
 }
 #endif /* defined(HAVE_SS7) */
 
+#if defined(HAVE_OPENR2)
+/*!
+ * \internal
+ * \brief Unlink the channel interface from the MFC/R2 private pointer array.
+ *
+ * \param pvt chan_dahdi private interface structure to unlink.
+ *
+ * \return Nothing
+ */
+static void dahdi_unlink_mfcr2_pvt(struct dahdi_pvt *pvt)
+{
+       unsigned idx;
+       struct dahdi_mfcr2 *mfcr2;
+       int should_destroy_link = 0;
+
+       ast_mutex_lock(&pvt->lock);
+       if (pvt->r2chan) {
+               ast_debug(1, "Disable MFC/R2 channel %d read\n", pvt->channel);
+               openr2_chan_disable_read(pvt->r2chan);
+       }
+       mfcr2 = pvt->mfcr2;
+       if (mfcr2) {
+               for (idx = 0; idx < mfcr2->numchans; ++idx) {
+                       if (mfcr2->pvts[idx] == pvt) {
+                               ast_debug(1, "Removing MFC/R2 channel %d from the mfcr2 link\n", pvt->channel);
+                               mfcr2->pvts[idx] = NULL;
+                               mfcr2->live_chans--;
+                               break;
+                       }
+               }
+               if (!mfcr2->live_chans) {
+                       ast_debug(1, "MFC/R2 link is now empty\n");
+                       should_destroy_link = 1;
+               }
+       }
+       ast_mutex_unlock(&pvt->lock);
+       if (should_destroy_link) {
+               ast_debug(1, "MFC/R2 link is now empty\n");
+               mfcr2_queue_for_destruction(pvt);
+       }
+}
+#endif /* defined(HAVE_OPENR2) */
+
 static struct dahdi_pvt *find_next_iface_in_span(struct dahdi_pvt *cur)
 {
        if (cur->next && cur->next->span == cur->span) {
@@ -5518,6 +5582,9 @@ static void destroy_dahdi_pvt(struct dahdi_pvt *pvt)
 #endif /* defined(HAVE_PRI) */
 #if defined(HAVE_SS7)
        dahdi_unlink_ss7_pvt(p);
+#endif /* defined(HAVE_SS7) */
+#if defined(HAVE_OPENR2)
+       dahdi_unlink_mfcr2_pvt(p);
 #endif /* defined(HAVE_SS7) */
        switch (pvt->which_iflist) {
        case DAHDI_IFLIST_NONE:
@@ -11032,6 +11099,40 @@ static void dahdi_destroy_channel_range(int start, int end)
        }
 }
 
+#ifdef HAVE_OPENR2
+static void dahdi_r2_destroy_nodev(void)
+{
+       struct r2link_entry *cur;
+       AST_LIST_LOCK(&nodev_r2links);
+       AST_LIST_TRAVERSE_SAFE_BEGIN(&nodev_r2links, cur, list) {
+               int i;
+               struct dahdi_mfcr2 *r2 = &cur->mfcr2;
+               ast_debug(3, "About to destroy %d DAHDI channels of MFC/R2 link.\n", r2->numchans);
+               for (i = 0; i < r2->numchans; i++) {
+                       int channel;
+                       struct dahdi_pvt *pvt = r2->pvts[i];
+                       if (!pvt) {
+                               continue;
+                       }
+                       channel = pvt->channel;
+                       ast_debug(3, "About to destroy B-channel %d.\n", channel);
+                       dahdi_destroy_channel_range(channel, channel);
+               }
+               ast_debug(3, "Destroying R2 link\n");
+               AST_LIST_REMOVE(&nodev_r2links, cur, list);
+               if (r2->r2master != AST_PTHREADT_NULL) {
+                       pthread_cancel(r2->r2master);
+                       pthread_join(r2->r2master, NULL);
+                       r2->r2master = AST_PTHREADT_NULL;
+                       openr2_context_delete(r2->protocol_context);
+               }
+               ast_free(cur);
+       }
+       AST_LIST_TRAVERSE_SAFE_END;
+       AST_LIST_UNLOCK(&nodev_r2links);
+}
+#endif
+
 static int setup_dahdi(int reload);
 static int setup_dahdi_int(int reload, struct dahdi_chan_conf *default_conf, struct dahdi_chan_conf *base_conf, struct dahdi_chan_conf *conf);
 
@@ -11655,6 +11756,9 @@ static void *do_monitor(void *data)
                }
                ast_mutex_unlock(&iflock);
                release_doomed_pris();
+#ifdef HAVE_OPENR2
+               dahdi_r2_destroy_nodev();
+#endif
        }
        /* Never reached */
        pthread_cleanup_pop(1);
@@ -11841,21 +11945,17 @@ static struct dahdi_ss7 * ss7_resolve_linkset(int linkset)
 static void dahdi_r2_destroy_links(void)
 {
        struct r2link_entry *cur;
+
+       /* Queue everything for removal */
        AST_LIST_LOCK(&r2links);
        AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links, cur, list) {
-               struct dahdi_mfcr2 *r2 = &cur->mfcr2;
-               ast_debug(3, "Destroying R2 link\n");
-               AST_LIST_REMOVE(&r2links, cur, list);
-               if (r2->r2master != AST_PTHREADT_NULL) {
-                       pthread_cancel(r2->r2master);
-                       pthread_join(r2->r2master, NULL);
-                       openr2_context_delete(r2->protocol_context);
-               }
-               ast_free(cur);
+               ast_debug(3, "MFC/R2 link #%d queued for destruction\n", cur->mfcr2.index);
+               AST_LIST_MOVE_CURRENT(&nodev_r2links, list);
        }
        AST_LIST_TRAVERSE_SAFE_END;
        AST_LIST_UNLOCK(&r2links);
-       r2links_count = 0;
+       /* Now destroy properly */
+       dahdi_r2_destroy_nodev();
 }
 
 /* This is an artificial convenient capacity, to keep at most a full E1 of channels in a single thread */
@@ -12189,6 +12289,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
                                        destroy_dahdi_pvt(tmp);
                                        return NULL;
                                }
+                               r2_link->live_chans++;
                                tmp->mfcr2 = r2_link;
                                if (conf->mfcr2.call_files) {
                                        openr2_chan_enable_call_files(tmp->r2chan);
@@ -13750,6 +13851,8 @@ static void dahdi_ss7_error(struct ss7 *ss7, char *s)
 static void *mfcr2_monitor(void *data)
 {
        struct dahdi_mfcr2 *mfcr2 = data;
+       struct dahdi_pvt *pvt;
+
        /* we should be using pthread_key_create
           and allocate pollers dynamically.
           I think do_monitor() could be leaking, since it
@@ -13766,8 +13869,12 @@ static void *mfcr2_monitor(void *data)
        /* now that we're ready to get calls, unblock our side and
           get current line state */
        for (i = 0; i < mfcr2->numchans; i++) {
-               openr2_chan_set_idle(mfcr2->pvts[i]->r2chan);
-               openr2_chan_handle_cas(mfcr2->pvts[i]->r2chan);
+               pvt = mfcr2->pvts[i];
+               if (!pvt) {
+                       continue;
+               }
+               openr2_chan_set_idle(pvt->r2chan);
+               openr2_chan_handle_cas(pvt->r2chan);
        }
        while (1) {
                /* we trust here that the mfcr2 channel list will not ever change once
@@ -13776,20 +13883,24 @@ static void *mfcr2_monitor(void *data)
                for (i = 0; i < mfcr2->numchans; i++) {
                        pollers[i].revents = 0;
                        pollers[i].events = 0;
-                       if (mfcr2->pvts[i]->owner) {
+                       pvt = mfcr2->pvts[i];
+                       if (!pvt) {
+                               continue;
+                       }
+                       if (pvt->owner) {
                                continue;
                        }
                        if (mfcr2->nodev) {
                                continue;
                        }
-                       if (!mfcr2->pvts[i]->r2chan) {
-                               ast_debug(1, "Wow, no r2chan on channel %d\n", mfcr2->pvts[i]->channel);
+                       if (!pvt->r2chan) {
+                               ast_debug(1, "Wow, no r2chan on channel %d\n", pvt->channel);
                                quit_loop = 1;
                                break;
                        }
-                       openr2_chan_enable_read(mfcr2->pvts[i]->r2chan);
+                       openr2_chan_enable_read(pvt->r2chan);
                        pollers[i].events = POLLIN | POLLPRI;
-                       pollers[i].fd = mfcr2->pvts[i]->subs[SUB_REAL].dfd;
+                       pollers[i].fd = pvt->subs[SUB_REAL].dfd;
                        pollsize++;
                }
                if (quit_loop) {
@@ -13816,8 +13927,12 @@ static void *mfcr2_monitor(void *data)
                /* do we want to allow to cancel while processing events? */
                pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
                for (i = 0; i < mfcr2->numchans; i++) {
+                       pvt = mfcr2->pvts[i];
+                       if (!pvt) {
+                               continue;
+                       }
                        if (pollers[i].revents & POLLPRI || pollers[i].revents & POLLIN) {
-                               openr2_chan_process_event(mfcr2->pvts[i]->r2chan);
+                               openr2_chan_process_event(pvt->r2chan);
                        }
                }
                pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
@@ -15121,6 +15236,51 @@ static char *handle_mfcr2_show_links(struct ast_cli_entry *e, int cmd, struct as
        return CLI_SUCCESS;
 }
 
+static char *handle_mfcr2_destroy_link(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+       int res;
+       int wanted_link_index;
+       int found_link = 0;
+       struct r2link_entry *cur = NULL;
+
+       switch (cmd) {
+       case CLI_INIT:
+               e->command = "mfcr2 destroy link";
+               e->usage =
+                       "Usage: mfcr2 destroy link <index-number>\n"
+                       "       Destorys D-channel of link and its B-channels.\n"
+                       "       DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n";
+               return NULL;
+       case CLI_GENERATE:
+               return NULL;
+       }
+       if (a->argc < 4) {
+               return CLI_SHOWUSAGE;
+       }
+       res = sscanf(a->argv[3], "%30d", &wanted_link_index);
+       if ((res != 1) || wanted_link_index < 1) {
+               ast_cli(a->fd,
+                       "Invalid link index '%s'.  Should be a positive number\n", a->argv[3]);
+               return CLI_SUCCESS;
+       }
+       AST_LIST_LOCK(&r2links);
+       AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links, cur, list) {
+               struct dahdi_mfcr2 *mfcr2 = &cur->mfcr2;
+               if (wanted_link_index == mfcr2->index) {
+                       AST_LIST_MOVE_CURRENT(&nodev_r2links, list);
+                       r2links_count--;
+                       break;
+               }
+       }
+       AST_LIST_TRAVERSE_SAFE_END;
+       AST_LIST_UNLOCK(&r2links);
+       if (! found_link) {
+               ast_cli(a->fd, "No link found with index %d.\n", wanted_link_index);
+               return CLI_FAILURE;
+       }
+       return CLI_SUCCESS;
+}
+
 static struct ast_cli_entry dahdi_mfcr2_cli[] = {
        AST_CLI_DEFINE(handle_mfcr2_version, "Show OpenR2 library version"),
        AST_CLI_DEFINE(handle_mfcr2_show_variants, "Show supported MFC/R2 variants"),
@@ -15130,6 +15290,7 @@ static struct ast_cli_entry dahdi_mfcr2_cli[] = {
        AST_CLI_DEFINE(handle_mfcr2_call_files, "Enable/Disable MFC/R2 call files"),
        AST_CLI_DEFINE(handle_mfcr2_set_idle, "Reset MFC/R2 channel forcing it to IDLE"),
        AST_CLI_DEFINE(handle_mfcr2_set_blocked, "Reset MFC/R2 channel forcing it to BLOCKED"),
+       AST_CLI_DEFINE(handle_mfcr2_destroy_link, "Destroy given MFC/R2 link"),
 };
 
 #endif /* HAVE_OPENR2 */
@@ -19437,13 +19598,15 @@ static int setup_dahdi_int(int reload, struct dahdi_chan_conf *default_conf, str
                AST_LIST_LOCK(&r2links);
                AST_LIST_TRAVERSE(&r2links, cur, list) {
                        struct dahdi_mfcr2 *r2 = &cur->mfcr2;
-                       if (ast_pthread_create(&r2->r2master, NULL, mfcr2_monitor, r2)) {
-                               ast_log(LOG_ERROR, "Unable to start R2 monitor on channel group %d\n", x + 1);
-                               return -1;
-                       } else {
-                               ast_verb(2, "Starting R2 monitor on channel group %d\n", x + 1);
+                       if (r2->r2master == AST_PTHREADT_NULL) {
+                               if (ast_pthread_create(&r2->r2master, NULL, mfcr2_monitor, r2)) {
+                                       ast_log(LOG_ERROR, "Unable to start R2 monitor on channel group %d\n", x + 1);
+                                       return -1;
+                               } else {
+                                       ast_verb(2, "Starting R2 monitor on channel group %d\n", x + 1);
+                               }
+                               x++;
                        }
-                       x++;
                }
                AST_LIST_UNLOCK(&r2links);
        }