<p>George Joseph <strong>merged</strong> this change.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/11607">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Kevin Harwell: Looks good to me, but someone else must approve
  Joshua Colp: Looks good to me, but someone else must approve
  George Joseph: Looks good to me, approved; Approved for Submit

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">openr2(5/6): added cli command -- mfcr2 destroy link <index><br><br>Change-Id: I452d6a853bcd8c6e194455b19e5e017713e9c0fe<br>Signed-off-by: Oron Peled <oron.peled@xorcom.com><br>---<br>M channels/chan_dahdi.c<br>1 file changed, 187 insertions(+), 24 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c</span><br><span>index 789d4f9..7ee561e 100644</span><br><span>--- a/channels/chan_dahdi.c</span><br><span>+++ b/channels/chan_dahdi.c</span><br><span>@@ -749,6 +749,7 @@</span><br><span>        openr2_context_t *protocol_context;    /*!< OpenR2 context handle */</span><br><span>      struct dahdi_pvt *pvts[SIG_MFCR2_MAX_CHANNELS];     /*!< Member channel pvt structs */</span><br><span>    int numchans;                          /*!< Number of channels in this R2 block */</span><br><span style="color: hsl(120, 100%, 40%);">+ int live_chans;                        /*!< Number of unremoved channels in this R2 block */</span><br><span>      int nodev;                             /*!< Link disconnected? */</span><br><span>         struct dahdi_mfcr2_conf conf;          /*!< Configuration used to setup this pseudo-link */</span><br><span> };</span><br><span>@@ -758,6 +759,8 @@</span><br><span>   AST_LIST_ENTRY(r2link_entry) list;</span><br><span> };</span><br><span> static AST_LIST_HEAD_STATIC(r2links, r2link_entry);</span><br><span style="color: hsl(120, 100%, 40%);">+static struct r2links nodev_r2links = AST_LIST_HEAD_INIT_VALUE;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> </span><br><span> /* how many r2links have been malloc'd */</span><br><span> static int r2links_count = 0;</span><br><span>@@ -3548,6 +3551,21 @@</span><br><span> }</span><br><span> </span><br><span> #ifdef HAVE_OPENR2</span><br><span style="color: hsl(120, 100%, 40%);">+static void mfcr2_queue_for_destruction(const struct dahdi_pvt *p)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       const struct dahdi_mfcr2 *r2link = p->mfcr2;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct r2link_entry *cur;</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_LIST_LOCK(&r2links);</span><br><span style="color: hsl(120, 100%, 40%);">+  AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links, cur, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+               if (r2link == &cur->mfcr2) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_debug(3, "MFC/R2 channel %d queued for destruction\n", p->channel);</span><br><span style="color: hsl(120, 100%, 40%);">+                  AST_LIST_MOVE_CURRENT(&nodev_r2links, list);</span><br><span style="color: hsl(120, 100%, 40%);">+                      break;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_LIST_TRAVERSE_SAFE_END;</span><br><span style="color: hsl(120, 100%, 40%);">+   AST_LIST_UNLOCK(&r2links);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span> </span><br><span> static int dahdi_r2_answer(struct dahdi_pvt *p)</span><br><span> {</span><br><span>@@ -3633,6 +3651,9 @@</span><br><span>        p->inalarm = alarm ? 1 : 0;</span><br><span>       if (p->inalarm) {</span><br><span>                 res = get_alarms(p);</span><br><span style="color: hsl(120, 100%, 40%);">+          if (res == DAHDI_ALARM_NOTOPEN) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     mfcr2_queue_for_destruction(p);</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span>            handle_alarms(p, res);</span><br><span>       } else {</span><br><span>             handle_clear_alarms(p);</span><br><span>@@ -5490,6 +5511,49 @@</span><br><span> }</span><br><span> #endif /* defined(HAVE_SS7) */</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#if defined(HAVE_OPENR2)</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \internal</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Unlink the channel interface from the MFC/R2 private pointer array.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param pvt chan_dahdi private interface structure to unlink.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return Nothing</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static void dahdi_unlink_mfcr2_pvt(struct dahdi_pvt *pvt)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       unsigned idx;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct dahdi_mfcr2 *mfcr2;</span><br><span style="color: hsl(120, 100%, 40%);">+    int should_destroy_link = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_mutex_lock(&pvt->lock);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (pvt->r2chan) {</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_debug(1, "Disable MFC/R2 channel %d read\n", pvt->channel);</span><br><span style="color: hsl(120, 100%, 40%);">+          openr2_chan_disable_read(pvt->r2chan);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     mfcr2 = pvt->mfcr2;</span><br><span style="color: hsl(120, 100%, 40%);">+        if (mfcr2) {</span><br><span style="color: hsl(120, 100%, 40%);">+          for (idx = 0; idx < mfcr2->numchans; ++idx) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (mfcr2->pvts[idx] == pvt) {</span><br><span style="color: hsl(120, 100%, 40%);">+                             ast_debug(1, "Removing MFC/R2 channel %d from the mfcr2 link\n", pvt->channel);</span><br><span style="color: hsl(120, 100%, 40%);">+                          mfcr2->pvts[idx] = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                           mfcr2->live_chans--;</span><br><span style="color: hsl(120, 100%, 40%);">+                               break;</span><br><span style="color: hsl(120, 100%, 40%);">+                        }</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!mfcr2->live_chans) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  ast_debug(1, "MFC/R2 link is now empty\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                 should_destroy_link = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+              }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_mutex_unlock(&pvt->lock);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (should_destroy_link) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_debug(1, "MFC/R2 link is now empty\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         mfcr2_queue_for_destruction(pvt);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+#endif    /* defined(HAVE_OPENR2) */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static struct dahdi_pvt *find_next_iface_in_span(struct dahdi_pvt *cur)</span><br><span> {</span><br><span>         if (cur->next && cur->next->span == cur->span) {</span><br><span>@@ -5519,6 +5583,9 @@</span><br><span> #if defined(HAVE_SS7)</span><br><span>        dahdi_unlink_ss7_pvt(p);</span><br><span> #endif      /* defined(HAVE_SS7) */</span><br><span style="color: hsl(120, 100%, 40%);">+#if defined(HAVE_OPENR2)</span><br><span style="color: hsl(120, 100%, 40%);">+     dahdi_unlink_mfcr2_pvt(p);</span><br><span style="color: hsl(120, 100%, 40%);">+#endif      /* defined(HAVE_SS7) */</span><br><span>      switch (pvt->which_iflist) {</span><br><span>      case DAHDI_IFLIST_NONE:</span><br><span>              break;</span><br><span>@@ -11032,6 +11099,40 @@</span><br><span>    }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef HAVE_OPENR2</span><br><span style="color: hsl(120, 100%, 40%);">+static void dahdi_r2_destroy_nodev(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct r2link_entry *cur;</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_LIST_LOCK(&nodev_r2links);</span><br><span style="color: hsl(120, 100%, 40%);">+    AST_LIST_TRAVERSE_SAFE_BEGIN(&nodev_r2links, cur, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+         int i;</span><br><span style="color: hsl(120, 100%, 40%);">+                struct dahdi_mfcr2 *r2 = &cur->mfcr2;</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_debug(3, "About to destroy %d DAHDI channels of MFC/R2 link.\n", r2->numchans);</span><br><span style="color: hsl(120, 100%, 40%);">+              for (i = 0; i < r2->numchans; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    int channel;</span><br><span style="color: hsl(120, 100%, 40%);">+                  struct dahdi_pvt *pvt = r2->pvts[i];</span><br><span style="color: hsl(120, 100%, 40%);">+                       if (!pvt) {</span><br><span style="color: hsl(120, 100%, 40%);">+                           continue;</span><br><span style="color: hsl(120, 100%, 40%);">+                     }</span><br><span style="color: hsl(120, 100%, 40%);">+                     channel = pvt->channel;</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_debug(3, "About to destroy B-channel %d.\n", channel);</span><br><span style="color: hsl(120, 100%, 40%);">+                  dahdi_destroy_channel_range(channel, channel);</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_debug(3, "Destroying R2 link\n");</span><br><span style="color: hsl(120, 100%, 40%);">+               AST_LIST_REMOVE(&nodev_r2links, cur, list);</span><br><span style="color: hsl(120, 100%, 40%);">+               if (r2->r2master != AST_PTHREADT_NULL) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   pthread_cancel(r2->r2master);</span><br><span style="color: hsl(120, 100%, 40%);">+                      pthread_join(r2->r2master, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+                  r2->r2master = AST_PTHREADT_NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                  openr2_context_delete(r2->protocol_context);</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_free(cur);</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_LIST_TRAVERSE_SAFE_END;</span><br><span style="color: hsl(120, 100%, 40%);">+   AST_LIST_UNLOCK(&nodev_r2links);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static int setup_dahdi(int reload);</span><br><span> static int setup_dahdi_int(int reload, struct dahdi_chan_conf *default_conf, struct dahdi_chan_conf *base_conf, struct dahdi_chan_conf *conf);</span><br><span> </span><br><span>@@ -11655,6 +11756,9 @@</span><br><span>             }</span><br><span>            ast_mutex_unlock(&iflock);</span><br><span>               release_doomed_pris();</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef HAVE_OPENR2</span><br><span style="color: hsl(120, 100%, 40%);">+            dahdi_r2_destroy_nodev();</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span>    }</span><br><span>    /* Never reached */</span><br><span>  pthread_cleanup_pop(1);</span><br><span>@@ -11841,21 +11945,17 @@</span><br><span> static void dahdi_r2_destroy_links(void)</span><br><span> {</span><br><span>         struct r2link_entry *cur;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Queue everything for removal */</span><br><span>   AST_LIST_LOCK(&r2links);</span><br><span>         AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links, cur, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-         struct dahdi_mfcr2 *r2 = &cur->mfcr2;</span><br><span style="color: hsl(0, 100%, 40%);">-            ast_debug(3, "Destroying R2 link\n");</span><br><span style="color: hsl(0, 100%, 40%);">-         AST_LIST_REMOVE(&r2links, cur, list);</span><br><span style="color: hsl(0, 100%, 40%);">-               if (r2->r2master != AST_PTHREADT_NULL) {</span><br><span style="color: hsl(0, 100%, 40%);">-                     pthread_cancel(r2->r2master);</span><br><span style="color: hsl(0, 100%, 40%);">-                        pthread_join(r2->r2master, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-                    openr2_context_delete(r2->protocol_context);</span><br><span style="color: hsl(0, 100%, 40%);">-         }</span><br><span style="color: hsl(0, 100%, 40%);">-               ast_free(cur);</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_debug(3, "MFC/R2 link #%d queued for destruction\n", cur->mfcr2.index);</span><br><span style="color: hsl(120, 100%, 40%);">+              AST_LIST_MOVE_CURRENT(&nodev_r2links, list);</span><br><span>     }</span><br><span>    AST_LIST_TRAVERSE_SAFE_END;</span><br><span>  AST_LIST_UNLOCK(&r2links);</span><br><span style="color: hsl(0, 100%, 40%);">-  r2links_count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Now destroy properly */</span><br><span style="color: hsl(120, 100%, 40%);">+    dahdi_r2_destroy_nodev();</span><br><span> }</span><br><span> </span><br><span> /* This is an artificial convenient capacity, to keep at most a full E1 of channels in a single thread */</span><br><span>@@ -12189,6 +12289,7 @@</span><br><span>                                    destroy_dahdi_pvt(tmp);</span><br><span>                                      return NULL;</span><br><span>                                 }</span><br><span style="color: hsl(120, 100%, 40%);">+                             r2_link->live_chans++;</span><br><span>                            tmp->mfcr2 = r2_link;</span><br><span>                             if (conf->mfcr2.call_files) {</span><br><span>                                     openr2_chan_enable_call_files(tmp->r2chan);</span><br><span>@@ -13757,6 +13858,8 @@</span><br><span> static void *mfcr2_monitor(void *data)</span><br><span> {</span><br><span>      struct dahdi_mfcr2 *mfcr2 = data;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct dahdi_pvt *pvt;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     /* we should be using pthread_key_create</span><br><span>        and allocate pollers dynamically.</span><br><span>            I think do_monitor() could be leaking, since it</span><br><span>@@ -13773,8 +13876,12 @@</span><br><span>        /* now that we're ready to get calls, unblock our side and</span><br><span>          get current line state */</span><br><span>         for (i = 0; i < mfcr2->numchans; i++) {</span><br><span style="color: hsl(0, 100%, 40%);">-           openr2_chan_set_idle(mfcr2->pvts[i]->r2chan);</span><br><span style="color: hsl(0, 100%, 40%);">-             openr2_chan_handle_cas(mfcr2->pvts[i]->r2chan);</span><br><span style="color: hsl(120, 100%, 40%);">+         pvt = mfcr2->pvts[i];</span><br><span style="color: hsl(120, 100%, 40%);">+              if (!pvt) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             openr2_chan_set_idle(pvt->r2chan);</span><br><span style="color: hsl(120, 100%, 40%);">+         openr2_chan_handle_cas(pvt->r2chan);</span><br><span>      }</span><br><span>    while (1) {</span><br><span>          /* we trust here that the mfcr2 channel list will not ever change once</span><br><span>@@ -13783,20 +13890,24 @@</span><br><span>           for (i = 0; i < mfcr2->numchans; i++) {</span><br><span>                        pollers[i].revents = 0;</span><br><span>                      pollers[i].events = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-                  if (mfcr2->pvts[i]->owner) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    pvt = mfcr2->pvts[i];</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (!pvt) {</span><br><span style="color: hsl(120, 100%, 40%);">+                           continue;</span><br><span style="color: hsl(120, 100%, 40%);">+                     }</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (pvt->owner) {</span><br><span>                                 continue;</span><br><span>                    }</span><br><span>                    if (mfcr2->nodev) {</span><br><span>                               continue;</span><br><span>                    }</span><br><span style="color: hsl(0, 100%, 40%);">-                       if (!mfcr2->pvts[i]->r2chan) {</span><br><span style="color: hsl(0, 100%, 40%);">-                            ast_debug(1, "Wow, no r2chan on channel %d\n", mfcr2->pvts[i]->channel);</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (!pvt->r2chan) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                ast_debug(1, "Wow, no r2chan on channel %d\n", pvt->channel);</span><br><span>                           quit_loop = 1;</span><br><span>                               break;</span><br><span>                       }</span><br><span style="color: hsl(0, 100%, 40%);">-                       openr2_chan_enable_read(mfcr2->pvts[i]->r2chan);</span><br><span style="color: hsl(120, 100%, 40%);">+                        openr2_chan_enable_read(pvt->r2chan);</span><br><span>                     pollers[i].events = POLLIN | POLLPRI;</span><br><span style="color: hsl(0, 100%, 40%);">-                   pollers[i].fd = mfcr2->pvts[i]->subs[SUB_REAL].dfd;</span><br><span style="color: hsl(120, 100%, 40%);">+                     pollers[i].fd = pvt->subs[SUB_REAL].dfd;</span><br><span>                  pollsize++;</span><br><span>          }</span><br><span>            if (quit_loop) {</span><br><span>@@ -13823,8 +13934,12 @@</span><br><span>          /* do we want to allow to cancel while processing events? */</span><br><span>                 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);</span><br><span>               for (i = 0; i < mfcr2->numchans; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 pvt = mfcr2->pvts[i];</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (!pvt) {</span><br><span style="color: hsl(120, 100%, 40%);">+                           continue;</span><br><span style="color: hsl(120, 100%, 40%);">+                     }</span><br><span>                    if (pollers[i].revents & POLLPRI || pollers[i].revents & POLLIN) {</span><br><span style="color: hsl(0, 100%, 40%);">-                              openr2_chan_process_event(mfcr2->pvts[i]->r2chan);</span><br><span style="color: hsl(120, 100%, 40%);">+                              openr2_chan_process_event(pvt->r2chan);</span><br><span>                   }</span><br><span>            }</span><br><span>            pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);</span><br><span>@@ -15128,6 +15243,51 @@</span><br><span>     return CLI_SUCCESS;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static char *handle_mfcr2_destroy_link(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     int res;</span><br><span style="color: hsl(120, 100%, 40%);">+      int wanted_link_index;</span><br><span style="color: hsl(120, 100%, 40%);">+        int found_link = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct r2link_entry *cur = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    switch (cmd) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case CLI_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+                e->command = "mfcr2 destroy link";</span><br><span style="color: hsl(120, 100%, 40%);">+               e->usage =</span><br><span style="color: hsl(120, 100%, 40%);">+                 "Usage: mfcr2 destroy link <index-number>\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                  "       Destorys D-channel of link and its B-channels.\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                   "  DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n";</span><br><span style="color: hsl(120, 100%, 40%);">+               return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  case CLI_GENERATE:</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (a->argc < 4) {</span><br><span style="color: hsl(120, 100%, 40%);">+              return CLI_SHOWUSAGE;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     res = sscanf(a->argv[3], "%30d", &wanted_link_index);</span><br><span style="color: hsl(120, 100%, 40%);">+        if ((res != 1) || wanted_link_index < 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_cli(a->fd,</span><br><span style="color: hsl(120, 100%, 40%);">+                     "Invalid link index '%s'.  Should be a positive number\n", a->argv[3]);</span><br><span style="color: hsl(120, 100%, 40%);">+          return CLI_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_LIST_LOCK(&r2links);</span><br><span style="color: hsl(120, 100%, 40%);">+  AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links, cur, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+               struct dahdi_mfcr2 *mfcr2 = &cur->mfcr2;</span><br><span style="color: hsl(120, 100%, 40%);">+               if (wanted_link_index == mfcr2->index) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   AST_LIST_MOVE_CURRENT(&nodev_r2links, list);</span><br><span style="color: hsl(120, 100%, 40%);">+                      r2links_count--;</span><br><span style="color: hsl(120, 100%, 40%);">+                      break;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_LIST_TRAVERSE_SAFE_END;</span><br><span style="color: hsl(120, 100%, 40%);">+   AST_LIST_UNLOCK(&r2links);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (! found_link) {</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_cli(a->fd, "No link found with index %d.\n", wanted_link_index);</span><br><span style="color: hsl(120, 100%, 40%);">+             return CLI_FAILURE;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     return CLI_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static struct ast_cli_entry dahdi_mfcr2_cli[] = {</span><br><span>        AST_CLI_DEFINE(handle_mfcr2_version, "Show OpenR2 library version"),</span><br><span>       AST_CLI_DEFINE(handle_mfcr2_show_variants, "Show supported MFC/R2 variants"),</span><br><span>@@ -15137,6 +15297,7 @@</span><br><span>    AST_CLI_DEFINE(handle_mfcr2_call_files, "Enable/Disable MFC/R2 call files"),</span><br><span>       AST_CLI_DEFINE(handle_mfcr2_set_idle, "Reset MFC/R2 channel forcing it to IDLE"),</span><br><span>  AST_CLI_DEFINE(handle_mfcr2_set_blocked, "Reset MFC/R2 channel forcing it to BLOCKED"),</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_CLI_DEFINE(handle_mfcr2_destroy_link, "Destroy given MFC/R2 link"),</span><br><span> };</span><br><span> </span><br><span> #endif /* HAVE_OPENR2 */</span><br><span>@@ -19444,13 +19605,15 @@</span><br><span>          AST_LIST_LOCK(&r2links);</span><br><span>                 AST_LIST_TRAVERSE(&r2links, cur, list) {</span><br><span>                         struct dahdi_mfcr2 *r2 = &cur->mfcr2;</span><br><span style="color: hsl(0, 100%, 40%);">-                    if (ast_pthread_create(&r2->r2master, NULL, mfcr2_monitor, r2)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                ast_log(LOG_ERROR, "Unable to start R2 monitor on channel group %d\n", x + 1);</span><br><span style="color: hsl(0, 100%, 40%);">-                                return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-                      } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                                ast_verb(2, "Starting R2 monitor on channel group %d\n", x + 1);</span><br><span style="color: hsl(120, 100%, 40%);">+                    if (r2->r2master == AST_PTHREADT_NULL) {</span><br><span style="color: hsl(120, 100%, 40%);">+                           if (ast_pthread_create(&r2->r2master, NULL, mfcr2_monitor, r2)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                      ast_log(LOG_ERROR, "Unable to start R2 monitor on channel group %d\n", x + 1);</span><br><span style="color: hsl(120, 100%, 40%);">+                                      return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+                            } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                                      ast_verb(2, "Starting R2 monitor on channel group %d\n", x + 1);</span><br><span style="color: hsl(120, 100%, 40%);">+                            }</span><br><span style="color: hsl(120, 100%, 40%);">+                             x++;</span><br><span>                         }</span><br><span style="color: hsl(0, 100%, 40%);">-                       x++;</span><br><span>                 }</span><br><span>            AST_LIST_UNLOCK(&r2links);</span><br><span>       }</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/11607">change 11607</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/c/asterisk/+/11607"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 16 </div>
<div style="display:none"> Gerrit-Change-Id: I452d6a853bcd8c6e194455b19e5e017713e9c0fe </div>
<div style="display:none"> Gerrit-Change-Number: 11607 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Oron Peled <oron.peled@xorcom.com> </div>
<div style="display:none"> Gerrit-Reviewer: Friendly Automation </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Joshua Colp <jcolp@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Kevin Harwell <kharwell@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Tzafrir Cohen <tzafrir.cohen@xorcom.com> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>