<p>laforge <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/osmo-mgw/+/18898">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Jenkins Builder: Verified
  neels: Looks good to me, but someone else must approve
  laforge: Looks good to me, approved

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">endp: add E1 endpoint interlocking<br><br>E1 endpoint names also represent different rates, this may mean that<br>some rate / subslot combinations are not possible because they overlap<br>within nthe timeslot. When the equipment (BSC) is properly configured,<br>this will be no problem, however invalid configuration may cause the<br>selection of overlapping endpoints and this needs to be prevented, and<br>logged. Also rate counters need to be in place.<br><br>Change-Id: I18e90b10648a7e504371179ad144645fc82e1c27<br>Related: OS#2547<br>---<br>M include/osmocom/mgcp/mgcp_endp.h<br>M include/osmocom/mgcp/mgcp_ratectr.h<br>M src/libosmo-mgcp/mgcp_endp.c<br>M src/libosmo-mgcp/mgcp_protocol.c<br>M src/libosmo-mgcp/mgcp_ratectr.c<br>M src/libosmo-mgcp/mgcp_vty.c<br>6 files changed, 301 insertions(+), 27 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmocom/mgcp/mgcp_endp.h b/include/osmocom/mgcp/mgcp_endp.h</span><br><span>index 0f9110c..a58053a 100644</span><br><span>--- a/include/osmocom/mgcp/mgcp_endp.h</span><br><span>+++ b/include/osmocom/mgcp/mgcp_endp.h</span><br><span>@@ -110,3 +110,4 @@</span><br><span>                                         const struct mgcp_trunk *trunk);</span><br><span> struct mgcp_endpoint *mgcp_endp_by_name(int *cause, const char *epname,</span><br><span>                                    struct mgcp_config *cfg);</span><br><span style="color: hsl(120, 100%, 40%);">+bool mgcp_endp_avail(struct mgcp_endpoint *endp);</span><br><span>diff --git a/include/osmocom/mgcp/mgcp_ratectr.h b/include/osmocom/mgcp/mgcp_ratectr.h</span><br><span>index a579f5b..d0bc628 100644</span><br><span>--- a/include/osmocom/mgcp/mgcp_ratectr.h</span><br><span>+++ b/include/osmocom/mgcp/mgcp_ratectr.h</span><br><span>@@ -28,6 +28,7 @@</span><br><span>    MGCP_CRCX_FAIL_INVALID_CONN_OPTIONS,</span><br><span>         MGCP_CRCX_FAIL_CODEC_NEGOTIATION,</span><br><span>    MGCP_CRCX_FAIL_BIND_PORT,</span><br><span style="color: hsl(120, 100%, 40%);">+     MGCP_CRCX_FAIL_AVAIL,</span><br><span> };</span><br><span> </span><br><span> /* Global MCGP MDCX related rate counters */</span><br><span>@@ -45,7 +46,8 @@</span><br><span>  MGCP_MDCX_FAIL_NO_REMOTE_CONN_DESC,</span><br><span>  MGCP_MDCX_FAIL_START_RTP,</span><br><span>    MGCP_MDCX_FAIL_REJECTED_BY_POLICY,</span><br><span style="color: hsl(0, 100%, 40%);">-      MGCP_MDCX_DEFERRED_BY_POLICY</span><br><span style="color: hsl(120, 100%, 40%);">+  MGCP_MDCX_DEFERRED_BY_POLICY,</span><br><span style="color: hsl(120, 100%, 40%);">+ MGCP_MDCX_FAIL_AVAIL,</span><br><span> };</span><br><span> </span><br><span> /* Global MCGP DLCX related rate counters */</span><br><span>@@ -58,6 +60,7 @@</span><br><span>  MGCP_DLCX_FAIL_UNHANDLED_PARAM,</span><br><span>      MGCP_DLCX_FAIL_REJECTED_BY_POLICY,</span><br><span>   MGCP_DLCX_DEFERRED_BY_POLICY,</span><br><span style="color: hsl(120, 100%, 40%);">+ MGCP_DLCX_FAIL_AVAIL,</span><br><span> };</span><br><span> </span><br><span> /* NOTE: When adding counters, also the dump_ratectr_* routines in vty.c must be updated. */</span><br><span>diff --git a/src/libosmo-mgcp/mgcp_endp.c b/src/libosmo-mgcp/mgcp_endp.c</span><br><span>index 94d4083..5e7bebb 100644</span><br><span>--- a/src/libosmo-mgcp/mgcp_endp.c</span><br><span>+++ b/src/libosmo-mgcp/mgcp_endp.c</span><br><span>@@ -25,6 +25,33 @@</span><br><span> #include <osmocom/mgcp/mgcp_endp.h></span><br><span> #include <osmocom/mgcp/mgcp_trunk.h></span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#define E1_TIMESLOTS 32</span><br><span style="color: hsl(120, 100%, 40%);">+#define E1_RATE_MAX 64</span><br><span style="color: hsl(120, 100%, 40%);">+#define E1_OFFS_MAX 8</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* A 64k timeslot on an E1 line can be subdevied into the following</span><br><span style="color: hsl(120, 100%, 40%);">+ * subslot combinations:</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * subslot:                                          offset:</span><br><span style="color: hsl(120, 100%, 40%);">+ * [          ][          ][   16k    ][8k_subslot]  0</span><br><span style="color: hsl(120, 100%, 40%);">+ * [          ][   32k    ][_subslot__][8k_subslot]  1</span><br><span style="color: hsl(120, 100%, 40%);">+ * [          ][ subslot  ][   16k    ][8k_subslot]  2</span><br><span style="color: hsl(120, 100%, 40%);">+ * [   64k    ][__________][_subslot__][8k_subslot]  3</span><br><span style="color: hsl(120, 100%, 40%);">+ * [ timeslot ][          ][   16k    ][8k_subslot]  4</span><br><span style="color: hsl(120, 100%, 40%);">+ * [          ][   32K    ][_subslot__][8k_subslot]  5</span><br><span style="color: hsl(120, 100%, 40%);">+ * [          ][ subslot  ][   16k    ][8k_subslot]  6</span><br><span style="color: hsl(120, 100%, 40%);">+ * [          ][          ][ subslot  ][8k_subslot]  7</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Since overlapping assignment of subslots is not possible there is a limited</span><br><span style="color: hsl(120, 100%, 40%);">+ * set of subslot assignments possible. The e1_rates array lists the possible</span><br><span style="color: hsl(120, 100%, 40%);">+ * assignments as depicted above. Also each subslot assignment comes along with</span><br><span style="color: hsl(120, 100%, 40%);">+ * a bit offset in the E1 bitstream. The e1_offsets arrays lists the bit</span><br><span style="color: hsl(120, 100%, 40%);">+ * offsets. */</span><br><span style="color: hsl(120, 100%, 40%);">+static const uint8_t e1_rates[] =</span><br><span style="color: hsl(120, 100%, 40%);">+          { 64, 32, 32, 16, 16, 16, 16, 8, 8, 8, 8, 8, 8, 8, 8 };</span><br><span style="color: hsl(120, 100%, 40%);">+static const uint8_t e1_offsets[] =</span><br><span style="color: hsl(120, 100%, 40%);">+          { 0, 0, 4, 0, 2, 4, 6, 0, 1, 2, 3, 4, 5, 6, 7 };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Endpoint typeset definition */</span><br><span> const struct mgcp_endpoint_typeset ep_typeset = {</span><br><span>         /* Specify endpoint properties for RTP endpoint */</span><br><span>@@ -53,35 +80,13 @@</span><br><span> static char *gen_e1_epname(void *ctx, uint8_t trunk_nr, uint8_t ts_nr,</span><br><span>                     uint8_t ss_nr)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-   /* A 64k timeslot on an E1 line can be subdevied into the following</span><br><span style="color: hsl(0, 100%, 40%);">-      * subslot combinations:</span><br><span style="color: hsl(0, 100%, 40%);">-         *</span><br><span style="color: hsl(0, 100%, 40%);">-       * subslot:                                          offset:</span><br><span style="color: hsl(0, 100%, 40%);">-     * [          ][          ][   16k    ][8k_subslot]  0</span><br><span style="color: hsl(0, 100%, 40%);">-   * [          ][   32k    ][_subslot__][8k_subslot]  1</span><br><span style="color: hsl(0, 100%, 40%);">-   * [          ][ subslot  ][   16k    ][8k_subslot]  2</span><br><span style="color: hsl(0, 100%, 40%);">-   * [   64k    ][__________][_subslot__][8k_subslot]  3</span><br><span style="color: hsl(0, 100%, 40%);">-   * [ timeslot ][          ][   16k    ][8k_subslot]  4</span><br><span style="color: hsl(0, 100%, 40%);">-   * [          ][   32K    ][_subslot__][8k_subslot]  5</span><br><span style="color: hsl(0, 100%, 40%);">-   * [          ][ subslot  ][   16k    ][8k_subslot]  6</span><br><span style="color: hsl(0, 100%, 40%);">-   * [          ][          ][ subslot  ][8k_subslot]  7</span><br><span style="color: hsl(0, 100%, 40%);">-   *</span><br><span style="color: hsl(0, 100%, 40%);">-       * Since overlapping assignment of subsolts is not possible there is</span><br><span style="color: hsl(0, 100%, 40%);">-     * a limited set of subsolt assignments possible. The rates array</span><br><span style="color: hsl(0, 100%, 40%);">-        * lists the possible assignments as depicted above. Also each subslot</span><br><span style="color: hsl(0, 100%, 40%);">-   * assignment comes along with a bit offset in the E1 bitstream. The</span><br><span style="color: hsl(0, 100%, 40%);">-     * offsets arrays lists the bit offsets. */</span><br><span style="color: hsl(0, 100%, 40%);">-     static const uint8_t rates[] =</span><br><span style="color: hsl(0, 100%, 40%);">-          { 64, 32, 32, 16, 16, 16, 16, 8, 8, 8, 8, 8, 8, 8, 8 };</span><br><span style="color: hsl(0, 100%, 40%);">- static const uint8_t offsets[] =</span><br><span style="color: hsl(0, 100%, 40%);">-                { 0, 0, 4, 0, 2, 4, 6, 0, 1, 2, 3, 4, 5, 6, 7 };</span><br><span>     unsigned int rate;</span><br><span>   unsigned int offset;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        OSMO_ASSERT(ss_nr < sizeof(rates));</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(ss_nr < sizeof(e1_rates));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   rate = rates[ss_nr];</span><br><span style="color: hsl(0, 100%, 40%);">-    offset = offsets[ss_nr];</span><br><span style="color: hsl(120, 100%, 40%);">+      rate = e1_rates[ss_nr];</span><br><span style="color: hsl(120, 100%, 40%);">+       offset = e1_offsets[ss_nr];</span><br><span> </span><br><span>      return talloc_asprintf(ctx, "%s%u/s-%u/su%u-%u",</span><br><span>                   MGCP_ENDPOINT_PREFIX_E1_TRUNK, trunk_nr, ts_nr, rate, offset);</span><br><span>@@ -213,7 +218,9 @@</span><br><span> </span><br><span>     for (i = 0; i < trunk->number_endpoints; i++) {</span><br><span>                endp = trunk->endpoints[i];</span><br><span style="color: hsl(0, 100%, 40%);">-          if (endp->callid == NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+          /* A free endpoint must not serve a call already and it must</span><br><span style="color: hsl(120, 100%, 40%);">+           * be available. */</span><br><span style="color: hsl(120, 100%, 40%);">+           if (endp->callid == NULL && mgcp_endp_avail(endp))</span><br><span>                        return endp;</span><br><span>         }</span><br><span> </span><br><span>@@ -362,3 +369,247 @@</span><br><span>                *cause = 0;</span><br><span>  return endp;</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Get the E1 timeslot number from a given E1 endpoint name</span><br><span style="color: hsl(120, 100%, 40%);">+ * (e.g. ds/e1-0/s-30/su16-4), returns 0xff on error. */</span><br><span style="color: hsl(120, 100%, 40%);">+static uint8_t e1_ts_nr_from_epname(const char *epname)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        char buf[MGCP_ENDPOINT_MAXLEN + 1];</span><br><span style="color: hsl(120, 100%, 40%);">+   char *save_ptr = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+        char *buf_ptr = buf;</span><br><span style="color: hsl(120, 100%, 40%);">+  char *token;</span><br><span style="color: hsl(120, 100%, 40%);">+  unsigned long int res = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  strncpy(buf, epname, MGCP_ENDPOINT_MAXLEN);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ while (1) {</span><br><span style="color: hsl(120, 100%, 40%);">+           token = strtok_r(buf_ptr, "/", &save_ptr);</span><br><span style="color: hsl(120, 100%, 40%);">+              buf_ptr = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+               if (!token)</span><br><span style="color: hsl(120, 100%, 40%);">+                   break;</span><br><span style="color: hsl(120, 100%, 40%);">+                if (strncmp(token, "s-", 2) == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 errno = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                    res = strtoul(token + 2, NULL, 10);</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (errno == ERANGE || res > E1_TIMESLOTS)</span><br><span style="color: hsl(120, 100%, 40%);">+                         return 0xff;</span><br><span style="color: hsl(120, 100%, 40%);">+                  return (uint8_t) res;</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0xff;</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%);">+/* Get the E1 timeslot number from a given E1 endpoint name</span><br><span style="color: hsl(120, 100%, 40%);">+ * (e.g. ds/e1-0/s-30/su16-4), returns 0xff on error. */</span><br><span style="color: hsl(120, 100%, 40%);">+static uint8_t e1_rate_from_epname(const char *epname)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   char buf[MGCP_ENDPOINT_MAXLEN + 1];</span><br><span style="color: hsl(120, 100%, 40%);">+   char *save_ptr = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+        char *buf_ptr = buf;</span><br><span style="color: hsl(120, 100%, 40%);">+  char *token;</span><br><span style="color: hsl(120, 100%, 40%);">+  unsigned long int res = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+    unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     strncpy(buf, epname, MGCP_ENDPOINT_MAXLEN);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ while (1) {</span><br><span style="color: hsl(120, 100%, 40%);">+           token = strtok_r(buf_ptr, "/", &save_ptr);</span><br><span style="color: hsl(120, 100%, 40%);">+              buf_ptr = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+               if (!token)</span><br><span style="color: hsl(120, 100%, 40%);">+                   break;</span><br><span style="color: hsl(120, 100%, 40%);">+                if (strncmp(token, "su", 2) == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 errno = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                    res = strtoul(token + 2, NULL, 10);</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (errno == ERANGE || res > E1_RATE_MAX)</span><br><span style="color: hsl(120, 100%, 40%);">+                          return 0xff;</span><br><span style="color: hsl(120, 100%, 40%);">+                  /* Make sure the rate is a valid rate */</span><br><span style="color: hsl(120, 100%, 40%);">+                      for (i = 0; i < sizeof(e1_rates); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                           if (res == e1_rates[i])</span><br><span style="color: hsl(120, 100%, 40%);">+                                       return (uint8_t) res;</span><br><span style="color: hsl(120, 100%, 40%);">+                 }</span><br><span style="color: hsl(120, 100%, 40%);">+                     return 0xff;</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0xff;</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%);">+/* Get the E1 bitstream offset from a given E1 endpoint name</span><br><span style="color: hsl(120, 100%, 40%);">+ * (e.g. ds/e1-0/s-30/su16-4), returns 0xff on error. */</span><br><span style="color: hsl(120, 100%, 40%);">+static uint8_t e1_offs_from_epname(const char *epname)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  char buf[MGCP_ENDPOINT_MAXLEN + 1];</span><br><span style="color: hsl(120, 100%, 40%);">+   char *save_ptr = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+        char *buf_ptr = buf;</span><br><span style="color: hsl(120, 100%, 40%);">+  char *token;</span><br><span style="color: hsl(120, 100%, 40%);">+  unsigned long int res = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  strncpy(buf, epname, MGCP_ENDPOINT_MAXLEN);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ while (1) {</span><br><span style="color: hsl(120, 100%, 40%);">+           token = strtok_r(buf_ptr, "/", &save_ptr);</span><br><span style="color: hsl(120, 100%, 40%);">+              buf_ptr = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+               if (!token)</span><br><span style="color: hsl(120, 100%, 40%);">+                   break;</span><br><span style="color: hsl(120, 100%, 40%);">+                if (strncmp(token, "su", 2) == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 token = strstr(token, "-");</span><br><span style="color: hsl(120, 100%, 40%);">+                 if (!token)</span><br><span style="color: hsl(120, 100%, 40%);">+                           return 0xff;</span><br><span style="color: hsl(120, 100%, 40%);">+                  token += 1;</span><br><span style="color: hsl(120, 100%, 40%);">+                   errno = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                    res = strtoul(token, NULL, 10);</span><br><span style="color: hsl(120, 100%, 40%);">+                       if (errno == ERANGE || res > E1_OFFS_MAX)</span><br><span style="color: hsl(120, 100%, 40%);">+                          return 0xff;</span><br><span style="color: hsl(120, 100%, 40%);">+                  return (uint8_t) res;</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0xff;</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%);">+/* Get the E1 subslot number (internal) from a given E1 endpoint name</span><br><span style="color: hsl(120, 100%, 40%);">+ * (e.g. ds/e1-0/s-30/su16-4), returns 0xff on error. */</span><br><span style="color: hsl(120, 100%, 40%);">+static uint8_t e1_ss_nr_from_epname(const char *epname)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t rate;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t offs;</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     rate = e1_rate_from_epname(epname);</span><br><span style="color: hsl(120, 100%, 40%);">+   offs = e1_offs_from_epname(epname);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_static_assert(sizeof(e1_rates) == sizeof(e1_offsets), e1_rates_e1_offsets_size);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       for (i = 0; i < sizeof(e1_rates); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+           if ((e1_rates[i] == rate) && (e1_offsets[i] == offs))</span><br><span style="color: hsl(120, 100%, 40%);">+                 return i;</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%);">+   return 0xff;</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%);">+/* Check if the selected E1 endpoint is avalable, which means that none of</span><br><span style="color: hsl(120, 100%, 40%);">+ * the overlapping endpoints are currently serving a call. (if the system</span><br><span style="color: hsl(120, 100%, 40%);">+ * is properly configured such a situation should never ocurr!) */</span><br><span style="color: hsl(120, 100%, 40%);">+static bool endp_avail_e1(struct mgcp_endpoint *endp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        /* The following map shows the overlapping of the subslots and their</span><br><span style="color: hsl(120, 100%, 40%);">+   * respective rates. The numbers on the right running from top to bottom</span><br><span style="color: hsl(120, 100%, 40%);">+       * are the bit offsets in the whole 64k timeslot. The numbers inside the</span><br><span style="color: hsl(120, 100%, 40%);">+       * boxes symbolize the internal subslot number (array index) and the</span><br><span style="color: hsl(120, 100%, 40%);">+   * rate in the form: i:r where i is the subslot number and r the</span><br><span style="color: hsl(120, 100%, 40%);">+       * respective rate.</span><br><span style="color: hsl(120, 100%, 40%);">+    *</span><br><span style="color: hsl(120, 100%, 40%);">+     * +--------+--------+--------+--------+ 0</span><br><span style="color: hsl(120, 100%, 40%);">+     * |        |        |        |  7:8k  |</span><br><span style="color: hsl(120, 100%, 40%);">+       * |        |        + 3:16k  +--------+ 1</span><br><span style="color: hsl(120, 100%, 40%);">+     * |        |        |        |  8:8k  |</span><br><span style="color: hsl(120, 100%, 40%);">+       * |        | 1:32k  +--------+--------+ 2</span><br><span style="color: hsl(120, 100%, 40%);">+     * |        |        |        |  9:8k  |</span><br><span style="color: hsl(120, 100%, 40%);">+       * |        |        + 4:16k  +--------+ 3</span><br><span style="color: hsl(120, 100%, 40%);">+     * |        |        |        | 10:8k  |</span><br><span style="color: hsl(120, 100%, 40%);">+       * | 0:64k  +--------+--------+--------+ 4</span><br><span style="color: hsl(120, 100%, 40%);">+     * |        |        |        | 11:8k  |</span><br><span style="color: hsl(120, 100%, 40%);">+       * |        |        + 5:16k  +--------+ 5</span><br><span style="color: hsl(120, 100%, 40%);">+     * |        |        |        | 12:8k  |</span><br><span style="color: hsl(120, 100%, 40%);">+       * |        | 2:32k  +--------+--------+ 6</span><br><span style="color: hsl(120, 100%, 40%);">+     * |        |        |        | 13:8k  |</span><br><span style="color: hsl(120, 100%, 40%);">+       * |        |        + 6:16k  +--------+ 7</span><br><span style="color: hsl(120, 100%, 40%);">+     * |        |        |        | 14:8k  |</span><br><span style="color: hsl(120, 100%, 40%);">+       * +--------+--------+--------+--------+ 8</span><br><span style="color: hsl(120, 100%, 40%);">+     *</span><br><span style="color: hsl(120, 100%, 40%);">+     * The following array contains tables with the subslot numbers that must be</span><br><span style="color: hsl(120, 100%, 40%);">+   * unused for each subslot. During this test we do not have to check the</span><br><span style="color: hsl(120, 100%, 40%);">+       * endpoint we need to verify, only the overlaps need to be checked. This is</span><br><span style="color: hsl(120, 100%, 40%);">+   * also the reason why the related subslot number is missing from each each</span><br><span style="color: hsl(120, 100%, 40%);">+    * line. */</span><br><span style="color: hsl(120, 100%, 40%);">+   const int8_t interlock_tab[15][16] =</span><br><span style="color: hsl(120, 100%, 40%);">+          { { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, -1 },</span><br><span style="color: hsl(120, 100%, 40%);">+              { 0, 3, 4, 7, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1 },</span><br><span style="color: hsl(120, 100%, 40%);">+             { 0, 5, 6, 11, 12, 13, 14, -1, -1, -1, -1, -1, -1, -1, -1 },</span><br><span style="color: hsl(120, 100%, 40%);">+          { 0, 1, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },</span><br><span style="color: hsl(120, 100%, 40%);">+           { 0, 1, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },</span><br><span style="color: hsl(120, 100%, 40%);">+          { 0, 2, 11, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },</span><br><span style="color: hsl(120, 100%, 40%);">+         { 0, 2, 13, 14, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },</span><br><span style="color: hsl(120, 100%, 40%);">+         { 0, 1, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },</span><br><span style="color: hsl(120, 100%, 40%);">+          { 0, 1, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },</span><br><span style="color: hsl(120, 100%, 40%);">+          { 0, 1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },</span><br><span style="color: hsl(120, 100%, 40%);">+          { 0, 1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },</span><br><span style="color: hsl(120, 100%, 40%);">+          { 0, 2, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },</span><br><span style="color: hsl(120, 100%, 40%);">+          { 0, 2, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },</span><br><span style="color: hsl(120, 100%, 40%);">+          { 0, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },</span><br><span style="color: hsl(120, 100%, 40%);">+          { 0, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      const int8_t *interlock;</span><br><span style="color: hsl(120, 100%, 40%);">+      unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t ts_nr = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+    uint8_t ss_nr = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+    char *epname_check;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct mgcp_endpoint *endp_check;</span><br><span style="color: hsl(120, 100%, 40%);">+     bool available = true;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* This function must only be used with E1 type endpoints! */</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(endp->trunk->trunk_type == MGCP_TRUNK_E1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        ts_nr = e1_ts_nr_from_epname(endp->name);</span><br><span style="color: hsl(120, 100%, 40%);">+  ss_nr = e1_ss_nr_from_epname(endp->name);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (ts_nr == 0xff || ss_nr == 0xff) {</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGPENDP(endp, DLMGCP, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                     "cannot check endpoint availability, endpoint name not parseable!\n");</span><br><span style="color: hsl(120, 100%, 40%);">+             return false;</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%);">+   interlock = interlock_tab[ss_nr];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   for (i = 0; i < sizeof(interlock_tab[0]); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+           /* Detect row end */</span><br><span style="color: hsl(120, 100%, 40%);">+          if (interlock[i] == -1)</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%);">+              /* Pick overlapping endpoint to check */</span><br><span style="color: hsl(120, 100%, 40%);">+              epname_check =</span><br><span style="color: hsl(120, 100%, 40%);">+                    gen_e1_epname(endp, endp->trunk->trunk_nr, ts_nr,</span><br><span style="color: hsl(120, 100%, 40%);">+                             interlock[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+              endp_check = find_specific_endpoint(epname_check, endp->trunk);</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!endp_check) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    LOGPENDP(endp, DLMGCP, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                             "cannot check endpoint availability, overlapping endpoint:%s not found!\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                 epname_check);</span><br><span style="color: hsl(120, 100%, 40%);">+                       talloc_free(epname_check);</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%);">+             talloc_free(epname_check);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          /* Check if overlapping endpoint currently serves another call</span><br><span style="color: hsl(120, 100%, 40%);">+                 * (This is an exceptional situation, that should not occur</span><br><span style="color: hsl(120, 100%, 40%);">+            * in a properly configured environment!) */</span><br><span style="color: hsl(120, 100%, 40%);">+          if (endp_check->callid) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  LOGPENDP(endp, DLMGCP, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                             "endpoint unavailable - overlapping endpoint:%s already serves a call!\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                          endp_check->name);</span><br><span style="color: hsl(120, 100%, 40%);">+                        available = false;</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return available;</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%);">+/*! check if an endpoint is available for any kind of operation.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] endp endpoint to check.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns true if endpoint is avalable, false it is blocked for any reason. */</span><br><span style="color: hsl(120, 100%, 40%);">+bool mgcp_endp_avail(struct mgcp_endpoint *endp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      switch (endp->trunk->trunk_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case MGCP_TRUNK_VIRTUAL:</span><br><span style="color: hsl(120, 100%, 40%);">+              /* There are no obstacles that may render a virtual trunk</span><br><span style="color: hsl(120, 100%, 40%);">+              * endpoint unusable, so virtual trunk endpoints are always</span><br><span style="color: hsl(120, 100%, 40%);">+            * available */</span><br><span style="color: hsl(120, 100%, 40%);">+               return true;</span><br><span style="color: hsl(120, 100%, 40%);">+  case MGCP_TRUNK_E1:</span><br><span style="color: hsl(120, 100%, 40%);">+           return endp_avail_e1(endp);</span><br><span style="color: hsl(120, 100%, 40%);">+   default:</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(false);</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%);">+   return false;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/libosmo-mgcp/mgcp_protocol.c b/src/libosmo-mgcp/mgcp_protocol.c</span><br><span>index 1e393e2..f2fc20c 100644</span><br><span>--- a/src/libosmo-mgcp/mgcp_protocol.c</span><br><span>+++ b/src/libosmo-mgcp/mgcp_protocol.c</span><br><span>@@ -747,6 +747,10 @@</span><br><span>         int rc;</span><br><span> </span><br><span>  LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "CRCX: creating new connection ...\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!mgcp_endp_avail(endp)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_FAIL_AVAIL]);</span><br><span style="color: hsl(120, 100%, 40%);">+           return create_err_response(NULL, 501, "CRCX", p->trans);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> </span><br><span>        /* parse CallID C: and LocalParameters L: */</span><br><span>         for_each_line(line, p->save) {</span><br><span>@@ -1004,6 +1008,11 @@</span><br><span> </span><br><span>       LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "MDCX: modifying existing connection ...\n");</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+       if (!mgcp_endp_avail(endp)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         rate_ctr_inc(&rate_ctrs->ctr[MGCP_MDCX_FAIL_AVAIL]);</span><br><span style="color: hsl(120, 100%, 40%);">+           return create_err_response(NULL, 501, "MDCX", p->trans);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  /* Prohibit wildcarded requests */</span><br><span>   if (endp->wildcarded_req) {</span><br><span>               LOGPENDP(endp, DLMGCP, LOGL_ERROR,</span><br><span>@@ -1224,6 +1233,11 @@</span><br><span>  LOGPENDP(endp, DLMGCP, LOGL_NOTICE,</span><br><span>           "DLCX: deleting connection ...\n");</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+    if (!mgcp_endp_avail(endp)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         rate_ctr_inc(&rate_ctrs->ctr[MGCP_DLCX_FAIL_AVAIL]);</span><br><span style="color: hsl(120, 100%, 40%);">+           return create_err_response(NULL, 501, "DLCX", p->trans);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  /* Prohibit wildcarded requests */</span><br><span>   if (endp->wildcarded_req) {</span><br><span>               LOGPENDP(endp, DLMGCP, LOGL_ERROR,</span><br><span>diff --git a/src/libosmo-mgcp/mgcp_ratectr.c b/src/libosmo-mgcp/mgcp_ratectr.c</span><br><span>index 302786f..1a89c83 100644</span><br><span>--- a/src/libosmo-mgcp/mgcp_ratectr.c</span><br><span>+++ b/src/libosmo-mgcp/mgcp_ratectr.c</span><br><span>@@ -63,6 +63,7 @@</span><br><span>      [MGCP_CRCX_FAIL_INVALID_CONN_OPTIONS] = { "crcx:conn_opt", "connection options invalid." },</span><br><span>      [MGCP_CRCX_FAIL_CODEC_NEGOTIATION] = { "crcx:codec_nego", "codec negotiation failure." },</span><br><span>        [MGCP_CRCX_FAIL_BIND_PORT] = { "crcx:bind_port", "port bind failure." },</span><br><span style="color: hsl(120, 100%, 40%);">+  [MGCP_CRCX_FAIL_AVAIL] = { "crcx:unavailable", "endpoint unavailable." },</span><br><span> };</span><br><span> </span><br><span> const static struct rate_ctr_group_desc mgcp_crcx_ctr_group_desc = {</span><br><span>@@ -90,6 +91,7 @@</span><br><span>  [MGCP_MDCX_FAIL_START_RTP] = { "mdcx:start_rtp_failure", "failure to start RTP processing." },</span><br><span>   [MGCP_MDCX_FAIL_REJECTED_BY_POLICY] = { "mdcx:conn_rejected", "connection rejected by policy." },</span><br><span>        [MGCP_MDCX_DEFERRED_BY_POLICY] = { "mdcx:conn_deferred", "connection deferred by policy." },</span><br><span style="color: hsl(120, 100%, 40%);">+      [MGCP_MDCX_FAIL_AVAIL] = { "mdcx:unavailable", "endpoint unavailable." },</span><br><span> };</span><br><span> </span><br><span> const static struct rate_ctr_group_desc mgcp_mdcx_ctr_group_desc = {</span><br><span>@@ -111,6 +113,7 @@</span><br><span>        [MGCP_DLCX_FAIL_UNHANDLED_PARAM] = { "dlcx:unhandled_param", "unhandled parameter in DLCX command." },</span><br><span>   [MGCP_DLCX_FAIL_REJECTED_BY_POLICY] = { "dlcx:rejected", "connection deletion rejected by policy." },</span><br><span>    [MGCP_DLCX_DEFERRED_BY_POLICY] = { "dlcx:deferred", "connection deletion deferred by policy." },</span><br><span style="color: hsl(120, 100%, 40%);">+  [MGCP_DLCX_FAIL_AVAIL] = { "dlcx:unavailable", "endpoint unavailable." },</span><br><span> };</span><br><span> </span><br><span> const static struct rate_ctr_group_desc mgcp_dlcx_ctr_group_desc = {</span><br><span>diff --git a/src/libosmo-mgcp/mgcp_vty.c b/src/libosmo-mgcp/mgcp_vty.c</span><br><span>index 938eef5..cbff700 100644</span><br><span>--- a/src/libosmo-mgcp/mgcp_vty.c</span><br><span>+++ b/src/libosmo-mgcp/mgcp_vty.c</span><br><span>@@ -199,6 +199,8 @@</span><br><span> </span><br><span>   vty_out(vty, "%s trunk %d endpoint %s:%s",</span><br><span>                 trunk_type == MGCP_TRUNK_VIRTUAL ? "Virtual" : "E1", trunk_nr, endp->name, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+       vty_out(vty, "   Availability: %s%s",</span><br><span style="color: hsl(120, 100%, 40%);">+               mgcp_endp_avail(endp) ? "available" : "not in service", VTY_NEWLINE);</span><br><span> </span><br><span>        if (llist_empty(&endp->conns)) {</span><br><span>              vty_out(vty, "   No active connections%s", VTY_NEWLINE);</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-mgw/+/18898">change 18898</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.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.osmocom.org/c/osmo-mgw/+/18898"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-mgw </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I18e90b10648a7e504371179ad144645fc82e1c27 </div>
<div style="display:none"> Gerrit-Change-Number: 18898 </div>
<div style="display:none"> Gerrit-PatchSet: 11 </div>
<div style="display:none"> Gerrit-Owner: dexter <pmaier@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: dexter <pmaier@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: neels <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>