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

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">mgcp_e1: finish E1 support, add E1 support from libosmoabis<br><br>Currently only the endpoint handling for E1 exists, but there is no<br>actual code behind it that handles the E1 traffic.<br><br>Change-Id: I6b93809b5ac7d01af55888347dd787b0bc997ae1<br>Related: OS#2659<br>---<br>M configure.ac<br>M include/osmocom/mgcp/Makefile.am<br>M include/osmocom/mgcp/debug.h<br>M include/osmocom/mgcp/mgcp_conn.h<br>A include/osmocom/mgcp/mgcp_e1.h<br>M include/osmocom/mgcp/mgcp_endp.h<br>M include/osmocom/mgcp/mgcp_internal.h<br>M include/osmocom/mgcp/mgcp_ratectr.h<br>M include/osmocom/mgcp/mgcp_trunk.h<br>M src/libosmo-mgcp/Makefile.am<br>M src/libosmo-mgcp/mgcp_conn.c<br>A src/libosmo-mgcp/mgcp_e1.c<br>M src/libosmo-mgcp/mgcp_endp.c<br>M src/libosmo-mgcp/mgcp_network.c<br>M src/libosmo-mgcp/mgcp_protocol.c<br>M src/libosmo-mgcp/mgcp_ratectr.c<br>M src/libosmo-mgcp/mgcp_trunk.c<br>M src/libosmo-mgcp/mgcp_vty.c<br>M src/osmo-mgw/Makefile.am<br>M src/osmo-mgw/mgw_main.c<br>M tests/mgcp/Makefile.am<br>M tests/mgcp/mgcp_test.c<br>22 files changed, 1,076 insertions(+), 62 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/configure.ac b/configure.ac</span><br><span>index 7c63437..db44893 100644</span><br><span>--- a/configure.ac</span><br><span>+++ b/configure.ac</span><br><span>@@ -52,6 +52,8 @@</span><br><span> PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.1.0)</span><br><span> PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.1.0)</span><br><span> PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 0.6.0)</span><br><span style="color: hsl(120, 100%, 40%);">+PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 0.6.0)</span><br><span style="color: hsl(120, 100%, 40%);">+PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 0.6.0)</span><br><span> </span><br><span> AC_ARG_ENABLE(sanitize,</span><br><span>      [AS_HELP_STRING(</span><br><span>diff --git a/include/osmocom/mgcp/Makefile.am b/include/osmocom/mgcp/Makefile.am</span><br><span>index fb7654f..549ba87 100644</span><br><span>--- a/include/osmocom/mgcp/Makefile.am</span><br><span>+++ b/include/osmocom/mgcp/Makefile.am</span><br><span>@@ -10,4 +10,5 @@</span><br><span>    mgcp_trunk.h \</span><br><span>       debug.h \</span><br><span>    mgcp_ratectr.h \</span><br><span style="color: hsl(120, 100%, 40%);">+      mgcp_e1.h \</span><br><span>  $(NULL)</span><br><span>diff --git a/include/osmocom/mgcp/debug.h b/include/osmocom/mgcp/debug.h</span><br><span>index ddeb0dc..7044c1e 100644</span><br><span>--- a/include/osmocom/mgcp/debug.h</span><br><span>+++ b/include/osmocom/mgcp/debug.h</span><br><span>@@ -29,6 +29,7 @@</span><br><span> /* Debug Areas of the code */</span><br><span> enum {</span><br><span>  DRTP,</span><br><span style="color: hsl(120, 100%, 40%);">+ DE1,</span><br><span>         Debug_LastEntry,</span><br><span> };</span><br><span> </span><br><span>diff --git a/include/osmocom/mgcp/mgcp_conn.h b/include/osmocom/mgcp/mgcp_conn.h</span><br><span>index ff5a779..78d5ea8 100644</span><br><span>--- a/include/osmocom/mgcp/mgcp_conn.h</span><br><span>+++ b/include/osmocom/mgcp/mgcp_conn.h</span><br><span>@@ -124,3 +124,4 @@</span><br><span> void mgcp_conn_free_all(struct mgcp_endpoint *endp);</span><br><span> char *mgcp_conn_dump(struct mgcp_conn *conn);</span><br><span> struct mgcp_conn *mgcp_find_dst_conn(struct mgcp_conn *conn);</span><br><span style="color: hsl(120, 100%, 40%);">+struct mgcp_conn *mgcp_conn_get_oldest(struct mgcp_endpoint *endp);</span><br><span>diff --git a/include/osmocom/mgcp/mgcp_e1.h b/include/osmocom/mgcp/mgcp_e1.h</span><br><span>new file mode 100644</span><br><span>index 0000000..a4ae854</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/mgcp/mgcp_e1.h</span><br><span>@@ -0,0 +1,28 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</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[] = { 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[] = { 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 style="color: hsl(120, 100%, 40%);">+int mgcp_e1_init(struct mgcp_trunk *trunk, uint8_t ts_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+int mgcp_e1_endp_equip(struct mgcp_endpoint *endp, uint8_t ts, uint8_t ss, uint8_t offs);</span><br><span style="color: hsl(120, 100%, 40%);">+void mgcp_e1_endp_update(struct mgcp_endpoint *endp);</span><br><span style="color: hsl(120, 100%, 40%);">+void mgcp_e1_endp_release(struct mgcp_endpoint *endp);</span><br><span style="color: hsl(120, 100%, 40%);">+int mgcp_e1_send_rtp(struct mgcp_endpoint *endp, struct mgcp_rtp_codec *codec, struct msgb *msg);</span><br><span>diff --git a/include/osmocom/mgcp/mgcp_endp.h b/include/osmocom/mgcp/mgcp_endp.h</span><br><span>index c16ea4b..065494f 100644</span><br><span>--- a/include/osmocom/mgcp/mgcp_endp.h</span><br><span>+++ b/include/osmocom/mgcp/mgcp_endp.h</span><br><span>@@ -24,6 +24,7 @@</span><br><span> #pragma once</span><br><span> </span><br><span> #include <osmocom/core/msgb.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/i460_mux.h></span><br><span> </span><br><span> struct sockaddr_in;</span><br><span> struct mgcp_conn;</span><br><span>@@ -116,10 +117,23 @@</span><br><span> </span><br><span>   /*! MGCP_X_OSMO_IGN_* flags from 'X-Osmo-IGN:' header */</span><br><span>     uint32_t x_osmo_ign;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* E1 specific */</span><br><span style="color: hsl(120, 100%, 40%);">+     struct {</span><br><span style="color: hsl(120, 100%, 40%);">+              struct osmo_i460_schan_desc scd;</span><br><span style="color: hsl(120, 100%, 40%);">+              struct osmo_i460_subchan *schan;</span><br><span style="color: hsl(120, 100%, 40%);">+              struct osmo_fsm_inst *trau_sync_fi;</span><br><span style="color: hsl(120, 100%, 40%);">+           struct osmo_trau2rtp_state *trau_rtp_st;</span><br><span style="color: hsl(120, 100%, 40%);">+              uint8_t last_amr_ft;</span><br><span style="color: hsl(120, 100%, 40%);">+          struct mgcp_rtp_codec *last_codec;</span><br><span style="color: hsl(120, 100%, 40%);">+    } e1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> };</span><br><span> </span><br><span> struct mgcp_endpoint *mgcp_endp_alloc(struct mgcp_trunk *trunk, unsigned int index);</span><br><span> void mgcp_endp_release(struct mgcp_endpoint *endp);</span><br><span style="color: hsl(120, 100%, 40%);">+int mgcp_endp_claim(struct mgcp_endpoint *endp, const char *callid);</span><br><span style="color: hsl(120, 100%, 40%);">+void mgcp_endp_update(struct mgcp_endpoint *endp);</span><br><span> struct mgcp_endpoint *mgcp_endp_by_name_trunk(int *cause, const char *epname,</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>diff --git a/include/osmocom/mgcp/mgcp_internal.h b/include/osmocom/mgcp/mgcp_internal.h</span><br><span>index 3d7224e..86b2a57 100644</span><br><span>--- a/include/osmocom/mgcp/mgcp_internal.h</span><br><span>+++ b/include/osmocom/mgcp/mgcp_internal.h</span><br><span>@@ -71,6 +71,10 @@</span><br><span>  /* duration of a packet (FIXME: in which unit?) */</span><br><span>   uint32_t packet_duration;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Note: These states are not continuously updated, they serve as an</span><br><span style="color: hsl(120, 100%, 40%);">+   * information source to patch certain values in the RTP header. Do</span><br><span style="color: hsl(120, 100%, 40%);">+    * not use this state if constantly updated data about the RTP stream</span><br><span style="color: hsl(120, 100%, 40%);">+  * is needed. (see also mgcp_patch_and_count() */</span><br><span>    struct mgcp_rtp_stream_state in_stream;</span><br><span>      struct mgcp_rtp_stream_state out_stream;</span><br><span> </span><br><span>@@ -85,6 +89,13 @@</span><br><span>            int cycles;</span><br><span>  } stats;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+  /* Alternative values for RTP tx, in case no sufficient header</span><br><span style="color: hsl(120, 100%, 40%);">+         * information is available so the header needs to be generated</span><br><span style="color: hsl(120, 100%, 40%);">+        * locally (when just forwarding packets, the header of incoming</span><br><span style="color: hsl(120, 100%, 40%);">+       * data is just re-used) */</span><br><span style="color: hsl(120, 100%, 40%);">+   uint16_t alt_rtp_tx_sequence;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t alt_rtp_tx_ssrc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  bool patched_first_rtp_payload; /* FIXME: drop this, see OS#2459 */</span><br><span> };</span><br><span> </span><br><span>@@ -296,3 +307,5 @@</span><br><span>                    struct mgcp_rtp_state *state,</span><br><span>                        struct mgcp_rtp_end *rtp_end,</span><br><span>                        struct sockaddr_in *addr, struct msgb *msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define RTP_BUF_SIZE          4096</span><br><span>diff --git a/include/osmocom/mgcp/mgcp_ratectr.h b/include/osmocom/mgcp/mgcp_ratectr.h</span><br><span>index d0bc628..ff59ea4 100644</span><br><span>--- a/include/osmocom/mgcp/mgcp_ratectr.h</span><br><span>+++ b/include/osmocom/mgcp/mgcp_ratectr.h</span><br><span>@@ -29,6 +29,7 @@</span><br><span>    MGCP_CRCX_FAIL_CODEC_NEGOTIATION,</span><br><span>    MGCP_CRCX_FAIL_BIND_PORT,</span><br><span>    MGCP_CRCX_FAIL_AVAIL,</span><br><span style="color: hsl(120, 100%, 40%);">+ MGCP_CRCX_FAIL_CLAIM,</span><br><span> };</span><br><span> </span><br><span> /* Global MCGP MDCX related rate counters */</span><br><span>@@ -63,6 +64,13 @@</span><br><span>         MGCP_DLCX_FAIL_AVAIL,</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* Trunk-global E1 related counters */</span><br><span style="color: hsl(120, 100%, 40%);">+enum {</span><br><span style="color: hsl(120, 100%, 40%);">+        E1_I460_TRAU_RX_FAIL_CTR,</span><br><span style="color: hsl(120, 100%, 40%);">+        E1_I460_TRAU_TX_FAIL_CTR,</span><br><span style="color: hsl(120, 100%, 40%);">+        E1_I460_TRAU_MUX_EMPTY_CTR,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* NOTE: When adding counters, also the dump_ratectr_* routines in vty.c must be updated. */</span><br><span> </span><br><span> struct mgcp_ratectr_global {</span><br><span>@@ -79,6 +87,8 @@</span><br><span>     struct rate_ctr_group *mgcp_dlcx_ctr_group;</span><br><span>  /* Rate counter group which aggregates stats of individual RTP connections. */</span><br><span>       struct rate_ctr_group *all_rtp_conn_stats;</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Rate counter group which contains stats for E1 events (only valid for E1 trunks) */</span><br><span style="color: hsl(120, 100%, 40%);">+        struct rate_ctr_group *e1_stats;</span><br><span> };</span><br><span> </span><br><span> int mgcp_ratectr_global_alloc(void *ctx, struct mgcp_ratectr_global *ratectr);</span><br><span>diff --git a/include/osmocom/mgcp/mgcp_trunk.h b/include/osmocom/mgcp/mgcp_trunk.h</span><br><span>index aa6dd29..d99f801 100644</span><br><span>--- a/include/osmocom/mgcp/mgcp_trunk.h</span><br><span>+++ b/include/osmocom/mgcp/mgcp_trunk.h</span><br><span>@@ -1,5 +1,13 @@</span><br><span> #pragma once</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/i460_mux.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define LOGPTRUNK(trunk, cat, level, fmt, args...) \</span><br><span style="color: hsl(120, 100%, 40%);">+LOGP(cat, level, "trunk:%u " fmt, \</span><br><span style="color: hsl(120, 100%, 40%);">+     trunk ? trunk->trunk_nr : 0, \</span><br><span style="color: hsl(120, 100%, 40%);">+     ## args)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> enum mgcp_trunk_type {</span><br><span>    MGCP_TRUNK_VIRTUAL,</span><br><span>  MGCP_TRUNK_E1,</span><br><span>@@ -39,18 +47,32 @@</span><br><span>         int rtp_accept_all;</span><br><span> </span><br><span>      unsigned int number_endpoints;</span><br><span style="color: hsl(0, 100%, 40%);">-  unsigned int vty_number_endpoints;</span><br><span>   struct mgcp_endpoint **endpoints;</span><br><span> </span><br><span>        /* global rate counters to measure the trunks overall performance and health */</span><br><span>      struct mgcp_ratectr_trunk ratectr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  union {</span><br><span style="color: hsl(120, 100%, 40%);">+               /* Virtual trunk specific */</span><br><span style="color: hsl(120, 100%, 40%);">+          struct {</span><br><span style="color: hsl(120, 100%, 40%);">+                      unsigned int vty_number_endpoints;</span><br><span style="color: hsl(120, 100%, 40%);">+            } v;</span><br><span style="color: hsl(120, 100%, 40%);">+          /* E1 specific */</span><br><span style="color: hsl(120, 100%, 40%);">+             struct {</span><br><span style="color: hsl(120, 100%, 40%);">+                      unsigned int vty_line_nr;</span><br><span style="color: hsl(120, 100%, 40%);">+                     struct e1inp_line *line;</span><br><span style="color: hsl(120, 100%, 40%);">+                      bool ts_in_use[31];</span><br><span style="color: hsl(120, 100%, 40%);">+                   struct osmo_i460_timeslot i460_ts[31];</span><br><span style="color: hsl(120, 100%, 40%);">+                } e1;</span><br><span style="color: hsl(120, 100%, 40%);">+ };</span><br><span> };</span><br><span> </span><br><span> struct mgcp_trunk *mgcp_trunk_alloc(struct mgcp_config *cfg, enum mgcp_trunk_type ttype, int nr);</span><br><span style="color: hsl(0, 100%, 40%);">-int mgcp_trunk_alloc_endpts(struct mgcp_trunk *tcfg);</span><br><span style="color: hsl(120, 100%, 40%);">+int mgcp_trunk_equip(struct mgcp_trunk *trunk);</span><br><span> struct mgcp_trunk *mgcp_trunk_by_num(const struct mgcp_config *cfg, enum mgcp_trunk_type ttype, int nr);</span><br><span> struct mgcp_trunk *mgcp_trunk_by_name(const struct mgcp_config *cfg, const char *epname);</span><br><span> int e1_trunk_nr_from_epname(const char *epname);</span><br><span style="color: hsl(120, 100%, 40%);">+struct mgcp_trunk *mgcp_trunk_by_line_num(const struct mgcp_config *cfg, unsigned int num);</span><br><span> </span><br><span> /* The virtual trunk is always created on trunk id 0 for historical reasons,</span><br><span>  * use this define constant as ID when allocating a virtual trunk. Other</span><br><span>diff --git a/src/libosmo-mgcp/Makefile.am b/src/libosmo-mgcp/Makefile.am</span><br><span>index 77d0cdf..91b2bf6 100644</span><br><span>--- a/src/libosmo-mgcp/Makefile.am</span><br><span>+++ b/src/libosmo-mgcp/Makefile.am</span><br><span>@@ -10,6 +10,8 @@</span><br><span>   $(LIBOSMOGSM_CFLAGS) \</span><br><span>       $(LIBOSMOVTY_CFLAGS) \</span><br><span>       $(LIBOSMONETIF_CFLAGS) \</span><br><span style="color: hsl(120, 100%, 40%);">+      $(LIBOSMOABIS_CFLAGS) \</span><br><span style="color: hsl(120, 100%, 40%);">+       $(LIBOSMOTRAU_CFLAGS) \</span><br><span>      $(COVERAGE_CFLAGS) \</span><br><span>         $(NULL)</span><br><span> </span><br><span>@@ -18,6 +20,8 @@</span><br><span>      $(LIBOSMOGSM_LIBS) \</span><br><span>         $(LIBOSMOVTY_LIBS) \</span><br><span>         $(LIBOSMONETIF_LIBS) \</span><br><span style="color: hsl(120, 100%, 40%);">+        $(LIBOSMOABIS_LIBS) \</span><br><span style="color: hsl(120, 100%, 40%);">+ $(LIBOSMOTRAU_LIBS) \</span><br><span>        $(COVERAGE_LDFLAGS) \</span><br><span>        $(NULL)</span><br><span> </span><br><span>@@ -43,4 +47,5 @@</span><br><span>      mgcp_trunk.c \</span><br><span>       mgcp_ctrl.c \</span><br><span>        mgcp_ratectr.c \</span><br><span style="color: hsl(120, 100%, 40%);">+      mgcp_e1.c \</span><br><span>  $(NULL)</span><br><span>diff --git a/src/libosmo-mgcp/mgcp_conn.c b/src/libosmo-mgcp/mgcp_conn.c</span><br><span>index 6802b91..8c7918e 100644</span><br><span>--- a/src/libosmo-mgcp/mgcp_conn.c</span><br><span>+++ b/src/libosmo-mgcp/mgcp_conn.c</span><br><span>@@ -397,3 +397,13 @@</span><br><span> </span><br><span>      return NULL;</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! get oldest connection in the list.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] endp associated endpoint */</span><br><span style="color: hsl(120, 100%, 40%);">+struct mgcp_conn *mgcp_conn_get_oldest(struct mgcp_endpoint *endp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        if (llist_empty(&endp->conns))</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%);">+        return llist_last_entry(&endp->conns, struct mgcp_conn, entry);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/libosmo-mgcp/mgcp_e1.c b/src/libosmo-mgcp/mgcp_e1.c</span><br><span>new file mode 100644</span><br><span>index 0000000..1e227dc</span><br><span>--- /dev/null</span><br><span>+++ b/src/libosmo-mgcp/mgcp_e1.c</span><br><span>@@ -0,0 +1,687 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* E1 traffic handling */</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%);">+ * (C) 2020 by sysmocom s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Author: Philipp Maier</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 3 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU Affero General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.</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%);">+#include <osmocom/mgcp/mgcp_internal.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mgcp/mgcp_endp.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mgcp/mgcp_trunk.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mgcp/mgcp_conn.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/msgb.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/abis/e1_input.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/abis/abis.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/trau/trau_sync.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/trau/trau_frame.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/trau/trau_rtp.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mgcp/mgcp_conn.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/netif/rtp.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mgcp/debug.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mgcp/mgcp_e1.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/codec/codec.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define DEBUG_BITS_MAX 80</span><br><span style="color: hsl(120, 100%, 40%);">+#define DEBUG_BYTES_MAX 40</span><br><span style="color: hsl(120, 100%, 40%);">+#define DEBUG_E1_TS 0</span><br><span style="color: hsl(120, 100%, 40%);">+#define E1_TS_BYTES 160</span><br><span style="color: hsl(120, 100%, 40%);">+#define E1_TRAU_BITS 320</span><br><span style="color: hsl(120, 100%, 40%);">+#define E1_TRAU_BITS_MSGB 2048</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct mgcp_config *cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct e1inp_line_ops dummy_e1_line_ops = {</span><br><span style="color: hsl(120, 100%, 40%);">+       .sign_link_up = NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+ .sign_link_down = NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+       .sign_link = NULL,</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%);">+/* EFR idle frame */</span><br><span style="color: hsl(120, 100%, 40%);">+static const ubit_t idle_tf_efr[] = { 0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 1, 1, 0, 1, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 1, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 1, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* FR idle frame */</span><br><span style="color: hsl(120, 100%, 40%);">+static const ubit_t idle_tf_fr[] = { 0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 1, 1, 1, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 1, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               1, 0, 0, 0, 0, 0, 1, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Idle speech frame, see also GSM 08.60, chapter 3.4 */</span><br><span style="color: hsl(120, 100%, 40%);">+static const ubit_t idle_tf_spch[] = { 0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 0, 0, 0, 0, 0, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 0, 1, 1, 1, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       0, 0, 0, 0, 1, 0, 0, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       1, 1, 1, 1, 1, 1, 1, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* If the RTP transmission has dropouts for some reason the I.460 TX-Queue may</span><br><span style="color: hsl(120, 100%, 40%);">+ * run empty. In order to make sure that the TRAU frame transmission continues</span><br><span style="color: hsl(120, 100%, 40%);">+ * we generate idle TRAU frames here. */</span><br><span style="color: hsl(120, 100%, 40%);">+static void e1_i460_mux_empty_cb(struct osmo_i460_subchan *schan, void *user_data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct mgcp_endpoint *endp = user_data;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct rate_ctr_group *rate_ctrs = endp->trunk->ratectr.e1_stats;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct msgb *msg = msgb_alloc(E1_TRAU_BITS_MSGB, "E1-I.460-IDLE-TX-TRAU-frame");</span><br><span style="color: hsl(120, 100%, 40%);">+    uint8_t *ptr;</span><br><span style="color: hsl(120, 100%, 40%);">+ const uint8_t *ptr_ft;</span><br><span style="color: hsl(120, 100%, 40%);">+        enum osmo_trau_frame_type ft;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       rate_ctr_inc(&rate_ctrs->ctr[E1_I460_TRAU_MUX_EMPTY_CTR]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Choose an appropiate idle frame type */</span><br><span style="color: hsl(120, 100%, 40%);">+    ft = endp->e1.trau_rtp_st->type;</span><br><span style="color: hsl(120, 100%, 40%);">+        switch (ft) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case OSMO_TRAU16_FT_FR:</span><br><span style="color: hsl(120, 100%, 40%);">+               ptr_ft = idle_tf_fr;</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case OSMO_TRAU16_FT_EFR:</span><br><span style="color: hsl(120, 100%, 40%);">+              ptr_ft = idle_tf_efr;</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              /* FIXME: What about 8k subslots and AMR frames? */</span><br><span style="color: hsl(120, 100%, 40%);">+           ptr_ft = idle_tf_spch;</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%);">+   /* Put the replacement into a message buffer and enqueue it into the</span><br><span style="color: hsl(120, 100%, 40%);">+   * I.460 multiplexer */</span><br><span style="color: hsl(120, 100%, 40%);">+       ptr = msgb_put(msg, E1_TRAU_BITS);</span><br><span style="color: hsl(120, 100%, 40%);">+    memcpy(ptr, ptr_ft, E1_TRAU_BITS);</span><br><span style="color: hsl(120, 100%, 40%);">+    LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-IDLE-TX: enquing %u trau frame bits: %s...\n", msgb_length(msg),</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_ubit_dump(msgb_data(msg), msgb_length(msg) > DEBUG_BITS_MAX ? DEBUG_BITS_MAX : msgb_length(msg)));</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_i460_mux_enqueue(endp->e1.schan, msg);</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%);">+/* called by I.460 de-multeiplexer; feed output of I.460 demux into TRAU frame sync */</span><br><span style="color: hsl(120, 100%, 40%);">+static void e1_i460_demux_bits_cb(struct osmo_i460_subchan *schan, void *user_data, const ubit_t *bits,</span><br><span style="color: hsl(120, 100%, 40%);">+                            unsigned int num_bits)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct mgcp_endpoint *endp = user_data;</span><br><span style="color: hsl(120, 100%, 40%);">+       LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-RX: receiving %u bits from subslot: %s...\n", num_bits,</span><br><span style="color: hsl(120, 100%, 40%);">+            osmo_ubit_dump(bits, num_bits > DEBUG_BITS_MAX ? DEBUG_BITS_MAX : num_bits));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(endp->e1.trau_sync_fi);</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_trau_sync_rx_ubits(endp->e1.trau_sync_fi, bits, num_bits);</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%);">+/* called for each synchronized TRAU frame received; decode frame + convert to RTP</span><br><span style="color: hsl(120, 100%, 40%);">+ * (the resulting frame will be prepended with an all-zero (12-byte) rtp header) */</span><br><span style="color: hsl(120, 100%, 40%);">+static void sync_frame_out_cb(void *user_data, const ubit_t *bits, unsigned int num_bits)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct msgb *msg = msgb_alloc(RTP_BUF_SIZE, "RTP-rx-from-E1");</span><br><span style="color: hsl(120, 100%, 40%);">+      unsigned int rtp_hdr_len = sizeof(struct rtp_hdr);</span><br><span style="color: hsl(120, 100%, 40%);">+    struct mgcp_endpoint *endp = user_data;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct rate_ctr_group *rate_ctrs = endp->trunk->ratectr.e1_stats;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct mgcp_conn *conn_dst;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_trau_frame fr;</span><br><span style="color: hsl(120, 100%, 40%);">+    int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!bits || num_bits == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+           goto skip;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-RX: receiving %u TRAU frame bits from E1 subslot: %s...\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                num_bits, osmo_ubit_dump(bits, num_bits > DEBUG_BITS_MAX ? DEBUG_BITS_MAX : num_bits));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Decode TRAU frame */</span><br><span style="color: hsl(120, 100%, 40%);">+       switch (endp->e1.scd.rate) {</span><br><span style="color: hsl(120, 100%, 40%);">+       case OSMO_I460_RATE_8k:</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-RX: decoding 8k trau frame...\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                rc = osmo_trau_frame_decode_8k(&fr, bits, OSMO_TRAU_DIR_UL);</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case OSMO_I460_RATE_16k:</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-RX: decoding 16k trau frame...\n");</span><br><span style="color: hsl(120, 100%, 40%);">+               rc = osmo_trau_frame_decode_16k(&fr, bits, OSMO_TRAU_DIR_UL);</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              /* TRAU frames only exist in 8K or 16K subslots. */</span><br><span style="color: hsl(120, 100%, 40%);">+           OSMO_ASSERT(false);</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%);">+     if (rc != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-RX: unable to decode trau frame\n");</span><br><span style="color: hsl(120, 100%, 40%);">+              goto skip;</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 payload type is supported and what the expected lenth</span><br><span style="color: hsl(120, 100%, 40%);">+  * of the RTP payload will be. */</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-RX: decoded trau frame type: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                osmo_trau_frame_type_name(fr.type));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* Convert decoded trau frame to RTP frame */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_trau2rtp_state t2rs = {</span><br><span style="color: hsl(120, 100%, 40%);">+           .type = fr.type,</span><br><span style="color: hsl(120, 100%, 40%);">+      };</span><br><span style="color: hsl(120, 100%, 40%);">+    rc = osmo_trau2rtp(msgb_data(msg) + rtp_hdr_len, msg->data_len - rtp_hdr_len, &fr, &t2rs);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc <= 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-RX: unable to convert trau frame to RTP audio\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                goto skip;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_put(msg, rtp_hdr_len + rc);</span><br><span style="color: hsl(120, 100%, 40%);">+      LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-RX: encoded %u bytes of RTP audio: %s\n", rc,</span><br><span style="color: hsl(120, 100%, 40%);">+              osmo_hexdump(msgb_data(msg) + rtp_hdr_len, msgb_length(msg) - rtp_hdr_len));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* Forward RTP data to IP */</span><br><span style="color: hsl(120, 100%, 40%);">+  conn_dst = llist_first_entry(&endp->conns, struct mgcp_conn, entry);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!conn_dst) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGPENDP(endp, DE1, LOGL_DEBUG,</span><br><span style="color: hsl(120, 100%, 40%);">+                        "E1-I.460-RX: unable to forward RTP audio data from E1: no connection to forward an incoming RTP packet to\n");</span><br><span style="color: hsl(120, 100%, 40%);">+            goto skip;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(conn_dst->type == MGCP_CONN_TYPE_RTP);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       mgcp_send(endp, 1, NULL, msg, &conn_dst->u.rtp, &conn_dst->u.rtp);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+       return;</span><br><span style="color: hsl(120, 100%, 40%);">+skip:</span><br><span style="color: hsl(120, 100%, 40%);">+        rate_ctr_inc(&rate_ctrs->ctr[E1_I460_TRAU_RX_FAIL_CTR]);</span><br><span style="color: hsl(120, 100%, 40%);">+       msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+       return;</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%);">+/* Function to handle outgoing E1 traffic */</span><br><span style="color: hsl(120, 100%, 40%);">+static void e1_send(struct e1inp_ts *ts, struct mgcp_trunk *trunk)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct msgb *msg = msgb_alloc(E1_TS_BYTES, "E1-TX-timeslot-bytes");</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t *ptr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* Get E1 frame from I.460 multiplexer */</span><br><span style="color: hsl(120, 100%, 40%);">+     ptr = msgb_put(msg, E1_TS_BYTES);</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_i460_mux_out(&trunk->e1.i460_ts[ts->num - 1], ptr, E1_TS_BYTES);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#if DEBUG_E1_TS == 1</span><br><span style="color: hsl(120, 100%, 40%);">+       LOGPTRUNK(trunk, DE1, LOGL_DEBUG, "E1-TX: (ts:%u) sending %u bytes: %s...\n", ts->num, msgb_length(msg),</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_hexdump_nospc(msgb_data(msg),</span><br><span style="color: hsl(120, 100%, 40%);">+                               msgb_length(msg) > DEBUG_BYTES_MAX ? DEBUG_BYTES_MAX : msgb_length(msg)));</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Hand data over to the E1 stack */</span><br><span style="color: hsl(120, 100%, 40%);">+  msgb_enqueue(&ts->raw.tx_queue, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+  return;</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%);">+/* Callback function to handle incoming E1 traffic */</span><br><span style="color: hsl(120, 100%, 40%);">+static void e1_recv_cb(struct e1inp_ts *ts, struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct mgcp_trunk *trunk;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Find associated trunk */</span><br><span style="color: hsl(120, 100%, 40%);">+   trunk = mgcp_trunk_by_line_num(cfg, ts->line->num);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!trunk) {</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGP(DE1, LOGL_DEBUG, "E1-RX: unable to find a trunk for E1-line %u!\n", ts->line->num);</span><br><span style="color: hsl(120, 100%, 40%);">+              return;</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 incoming data looks sane */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (msgb_length(msg) != E1_TS_BYTES) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGPTRUNK(trunk, DE1, LOGL_NOTICE,</span><br><span style="color: hsl(120, 100%, 40%);">+                      "E1-RX: (ts:%u) expected length is %u, actual length is %u!\n", ts->num, E1_TS_BYTES,</span><br><span style="color: hsl(120, 100%, 40%);">+                    msgb_length(msg));</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+#if DEBUG_E1_TS == 1</span><br><span style="color: hsl(120, 100%, 40%);">+       LOGPTRUNK(trunk, DE1, LOGL_DEBUG, "E1-RX: (ts:%u) receiving %u bytes: %s...\n", ts->num,</span><br><span style="color: hsl(120, 100%, 40%);">+           msgb_length(msg), osmo_hexdump_nospc(msgb_data(msg),</span><br><span style="color: hsl(120, 100%, 40%);">+                                                       msgb_length(msg) ></span><br><span style="color: hsl(120, 100%, 40%);">+                                                 DEBUG_BYTES_MAX ? DEBUG_BYTES_MAX : msgb_length(msg)));</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Hand data over to the I.460 demultiplexer. */</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_i460_demux_in(&trunk->e1.i460_ts[ts->num - 1], msgb_data(msg), msgb_length(msg));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Trigger sending of pending E1 traffic */</span><br><span style="color: hsl(120, 100%, 40%);">+   e1_send(ts, trunk);</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%);">+/*! Find an endpoint by its name on a specified trunk.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] trunk trunk configuration.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] ts_nr E1 timeslot number.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns -EINVAL on failure, 0 on success. */</span><br><span style="color: hsl(120, 100%, 40%);">+int mgcp_e1_init(struct mgcp_trunk *trunk, uint8_t ts_nr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        /*! Each timeslot needs only to be configured once. The Timeslot then</span><br><span style="color: hsl(120, 100%, 40%);">+  *  stays open and permanently receives data. It is then up to the</span><br><span style="color: hsl(120, 100%, 40%);">+     *  I.460 demultiplexer to add/remove subchannels as needed. It is</span><br><span style="color: hsl(120, 100%, 40%);">+     *  allowed to call this function multiple times since we check if the</span><br><span style="color: hsl(120, 100%, 40%);">+         *  timeslot is already configured. */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      struct e1inp_line *e1_line;</span><br><span style="color: hsl(120, 100%, 40%);">+   int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(ts_nr > 0 || ts_nr < NUM_E1_TS);</span><br><span style="color: hsl(120, 100%, 40%);">+    cfg = trunk->cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (trunk->e1.ts_in_use[ts_nr - 1]) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGPTRUNK(trunk, DE1, LOGL_DEBUG, "E1 timeslot %u already set up, skipping...\n", ts_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+           return 0;</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 E1 line */</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!trunk->e1.line) {</span><br><span style="color: hsl(120, 100%, 40%);">+             e1_line = e1inp_line_find(trunk->e1.vty_line_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+          if (!e1_line) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       LOGPTRUNK(trunk, DE1, LOGL_DEBUG, "no such E1 line %u - check VTY config!\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                 trunk->e1.vty_line_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+                  return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+             e1inp_line_bind_ops(e1_line, &dummy_e1_line_ops);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else</span><br><span style="color: hsl(120, 100%, 40%);">+                e1_line = trunk->e1.line;</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!e1_line)</span><br><span style="color: hsl(120, 100%, 40%);">+         return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Configure E1 timeslot */</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = e1inp_ts_config_raw(&e1_line->ts[ts_nr - 1], e1_line, e1_recv_cb);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       e1inp_line_update(e1_line);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGPTRUNK(trunk, DE1, LOGL_DEBUG, "E1 timeslot %u set up successfully.\n", ts_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+  trunk->e1.ts_in_use[ts_nr - 1] = true;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</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%);">+/* Determine a suitable TRAU frame type for a given codec */</span><br><span style="color: hsl(120, 100%, 40%);">+static enum osmo_trau_frame_type determine_trau_fr_type(char *sdp_subtype_name, enum osmo_i460_rate i460_rate,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                  uint8_t amr_ft, struct mgcp_endpoint *endp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        if (strcmp(sdp_subtype_name, "GSM") == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+           return OSMO_TRAU16_FT_FR;</span><br><span style="color: hsl(120, 100%, 40%);">+     else if (strcmp(sdp_subtype_name, "GSM-EFR") == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+          return OSMO_TRAU16_FT_EFR;</span><br><span style="color: hsl(120, 100%, 40%);">+    else if (strcmp(sdp_subtype_name, "GSM-HR-08") == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                return OSMO_TRAU16_FT_HR;</span><br><span style="color: hsl(120, 100%, 40%);">+     else if (strcmp(sdp_subtype_name, "AMR") == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+            if (i460_rate == OSMO_I460_RATE_8k) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 switch (amr_ft) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     case AMR_4_75:</span><br><span style="color: hsl(120, 100%, 40%);">+                        case AMR_5_15:</span><br><span style="color: hsl(120, 100%, 40%);">+                        case AMR_5_90:</span><br><span style="color: hsl(120, 100%, 40%);">+                                return OSMO_TRAU8_AMR_LOW;</span><br><span style="color: hsl(120, 100%, 40%);">+                    case AMR_6_70:</span><br><span style="color: hsl(120, 100%, 40%);">+                                return OSMO_TRAU8_AMR_6k7;</span><br><span style="color: hsl(120, 100%, 40%);">+                    case AMR_7_40:</span><br><span style="color: hsl(120, 100%, 40%);">+                                return OSMO_TRAU8_AMR_7k4;</span><br><span style="color: hsl(120, 100%, 40%);">+                    default:</span><br><span style="color: hsl(120, 100%, 40%);">+                              LOGPENDP(endp, DE1, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                                        "E1-TRAU-TX: unsupported or illegal AMR frame type: %u\n", amr_ft);</span><br><span style="color: hsl(120, 100%, 40%);">+                                return OSMO_TRAU_FT_NONE;</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 OSMO_TRAU16_FT_AMR;</span><br><span style="color: hsl(120, 100%, 40%);">+    } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGPENDP(endp, DE1, LOGL_ERROR, "E1-TRAU-TX: unsupported or illegal codec subtype name: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                       sdp_subtype_name);</span><br><span style="color: hsl(120, 100%, 40%);">+           return OSMO_TRAU_FT_NONE;</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%);">+/* Determine a suitable TRAU frame type for a given codec */</span><br><span style="color: hsl(120, 100%, 40%);">+static enum osmo_tray_sync_pat_id determine_trau_sync_pat(char *sdp_subtype_name, enum osmo_i460_rate i460_rate,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                          uint8_t amr_ft, struct mgcp_endpoint *endp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      if (strcmp(sdp_subtype_name, "GSM") == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+           return OSMO_TRAU_SYNCP_16_FR_EFR;</span><br><span style="color: hsl(120, 100%, 40%);">+     else if (strcmp(sdp_subtype_name, "GSM-EFR") == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+          return OSMO_TRAU_SYNCP_16_FR_EFR;</span><br><span style="color: hsl(120, 100%, 40%);">+     else if (strcmp(sdp_subtype_name, "GSM-HR-08") == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                return OSMO_TRAU_SYNCP_8_HR;</span><br><span style="color: hsl(120, 100%, 40%);">+  else if (strcmp(sdp_subtype_name, "AMR") == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+            if (i460_rate == OSMO_I460_RATE_8k) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 switch (amr_ft) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     case AMR_4_75:</span><br><span style="color: hsl(120, 100%, 40%);">+                        case AMR_5_15:</span><br><span style="color: hsl(120, 100%, 40%);">+                        case AMR_5_90:</span><br><span style="color: hsl(120, 100%, 40%);">+                                return OSMO_TRAU_SYNCP_8_AMR_LOW;</span><br><span style="color: hsl(120, 100%, 40%);">+                     case AMR_6_70:</span><br><span style="color: hsl(120, 100%, 40%);">+                                return OSMO_TRAU_SYNCP_8_AMR_6K7;</span><br><span style="color: hsl(120, 100%, 40%);">+                     case AMR_7_40:</span><br><span style="color: hsl(120, 100%, 40%);">+                                return OSMO_TRAU_SYNCP_8_AMR_7K4;</span><br><span style="color: hsl(120, 100%, 40%);">+                     default:</span><br><span style="color: hsl(120, 100%, 40%);">+                              LOGPENDP(endp, DE1, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                                        "E1-TRAU-TX: unsupported or illegal AMR frame type: %u\n", amr_ft);</span><br><span style="color: hsl(120, 100%, 40%);">+                                return OSMO_TRAU_SYNCP_16_FR_EFR;</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 OSMO_TRAU_SYNCP_16_FR_EFR;</span><br><span style="color: hsl(120, 100%, 40%);">+     } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGPENDP(endp, DE1, LOGL_ERROR, "E1-TRAU-TX: unsupported or illegal codec subtype name: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                       sdp_subtype_name);</span><br><span style="color: hsl(120, 100%, 40%);">+           return OSMO_TRAU_SYNCP_16_FR_EFR;</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%);">+/* Find out if a given TRAU frame type is AMR */</span><br><span style="color: hsl(120, 100%, 40%);">+static bool tf_type_is_amr(enum osmo_trau_frame_type ft)</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%);">+       switch (ft) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case OSMO_TRAU16_FT_AMR:</span><br><span style="color: hsl(120, 100%, 40%);">+      case OSMO_TRAU8_AMR_LOW:</span><br><span style="color: hsl(120, 100%, 40%);">+      case OSMO_TRAU8_AMR_6k7:</span><br><span style="color: hsl(120, 100%, 40%);">+      case OSMO_TRAU8_AMR_7k4:</span><br><span style="color: hsl(120, 100%, 40%);">+              return true;</span><br><span style="color: hsl(120, 100%, 40%);">+  default:</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* !Equip E1 endpoint with I.460 mux resources.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] endp endpoint to equip</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] ts E1 timeslot number.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] ss E1 subslot number.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] offset E1 bit offset.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns 0 on success, -EINVAL on error. */</span><br><span style="color: hsl(120, 100%, 40%);">+int mgcp_e1_endp_equip(struct mgcp_endpoint *endp, uint8_t ts, uint8_t ss, uint8_t offs)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       enum osmo_tray_sync_pat_id sync_pat_id = OSMO_TRAU_SYNCP_16_FR_EFR;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(ts != 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(ts != 0xFF);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(ss != 0xFF);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(offs != 0xFF);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  memset(&endp->e1, 0, sizeof(endp->e1));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   endp->e1.last_amr_ft = AMR_4_75;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Set up E1 line / timeslot */</span><br><span style="color: hsl(120, 100%, 40%);">+       rc = mgcp_e1_init(endp->trunk, ts);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (rc != 0)</span><br><span style="color: hsl(120, 100%, 40%);">+          return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Set up I.460 mux */</span><br><span style="color: hsl(120, 100%, 40%);">+        switch (e1_rates[ss]) {</span><br><span style="color: hsl(120, 100%, 40%);">+       case 64:</span><br><span style="color: hsl(120, 100%, 40%);">+              endp->e1.scd.rate = OSMO_I460_RATE_64k;</span><br><span style="color: hsl(120, 100%, 40%);">+            endp->e1.scd.demux.num_bits = 160 * 8;</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case 32:</span><br><span style="color: hsl(120, 100%, 40%);">+              endp->e1.scd.rate = OSMO_I460_RATE_32k;</span><br><span style="color: hsl(120, 100%, 40%);">+            endp->e1.scd.demux.num_bits = 80 * 8;</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case 16:</span><br><span style="color: hsl(120, 100%, 40%);">+              endp->e1.scd.rate = OSMO_I460_RATE_16k;</span><br><span style="color: hsl(120, 100%, 40%);">+            endp->e1.scd.demux.num_bits = 40 * 8;</span><br><span style="color: hsl(120, 100%, 40%);">+              sync_pat_id = OSMO_TRAU_SYNCP_16_FR_EFR;</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case 8:</span><br><span style="color: hsl(120, 100%, 40%);">+               endp->e1.scd.rate = OSMO_I460_RATE_8k;</span><br><span style="color: hsl(120, 100%, 40%);">+             endp->e1.scd.demux.num_bits = 20 * 8;</span><br><span style="color: hsl(120, 100%, 40%);">+              sync_pat_id = OSMO_TRAU_SYNCP_8_HR;</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%);">+     endp->e1.scd.bit_offset = offs;</span><br><span style="color: hsl(120, 100%, 40%);">+    endp->e1.scd.demux.out_cb_bits = e1_i460_demux_bits_cb;</span><br><span style="color: hsl(120, 100%, 40%);">+    endp->e1.scd.demux.out_cb_bytes = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+    endp->e1.scd.demux.user_data = endp;</span><br><span style="color: hsl(120, 100%, 40%);">+       endp->e1.scd.mux.in_cb_queue_empty = e1_i460_mux_empty_cb;</span><br><span style="color: hsl(120, 100%, 40%);">+ endp->e1.scd.mux.user_data = endp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       LOGPENDP(endp, DE1, LOGL_DEBUG, "adding I.460 subchannel: ts=%u, bit_offset=%u, rate=%uk, num_bits=%lu\n", ts,</span><br><span style="color: hsl(120, 100%, 40%);">+               offs, e1_rates[ss], endp->e1.scd.demux.num_bits);</span><br><span style="color: hsl(120, 100%, 40%);">+ endp->e1.schan = osmo_i460_subchan_add(endp, &endp->trunk->e1.i460_ts[ts - 1], &endp->e1.scd);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!endp->e1.schan) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGPENDP(endp, DE1, LOGL_ERROR, "adding I.460 subchannel: failed!\n");</span><br><span style="color: hsl(120, 100%, 40%);">+              return -EINVAL;</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 (endp->e1.scd.rate == OSMO_I460_RATE_16k || endp->e1.scd.rate == OSMO_I460_RATE_8k) {</span><br><span style="color: hsl(120, 100%, 40%);">+                /* TRAU frames are only specified for 16k and 8k subslots. For all other subslot</span><br><span style="color: hsl(120, 100%, 40%);">+               * types the concept of TRAU frames does not apply. However, at the moment this</span><br><span style="color: hsl(120, 100%, 40%);">+                * is the only format we currently support in osmo-mgw */</span><br><span style="color: hsl(120, 100%, 40%);">+             endp->e1.trau_sync_fi = osmo_trau_sync_alloc(endp, "trau-sync", sync_frame_out_cb, sync_pat_id, endp);</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!endp->e1.trau_sync_fi) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGPENDP(endp, DE1, LOGL_ERROR, "adding I.460 TRAU frame sync: failed!\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                 return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+             endp->e1.trau_rtp_st = talloc_zero(endp->e1.trau_sync_fi, struct osmo_trau2rtp_state);</span><br><span style="color: hsl(120, 100%, 40%);">+          endp->e1.trau_rtp_st->type = OSMO_TRAU_FT_NONE;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGPENDP(endp, DE1, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                        "osmo-mgw currently only supports 16K and 8K subslots (TRAU frames)!\n");</span><br><span style="color: hsl(120, 100%, 40%);">+          return -EINVAL;</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 0;</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%);">+/*! Update E1 related parameters (codec and sync pattern).</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] endp endpoint to update. */</span><br><span style="color: hsl(120, 100%, 40%);">+void mgcp_e1_endp_update(struct mgcp_endpoint *endp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct mgcp_conn *conn;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct mgcp_rtp_codec *codec;</span><br><span style="color: hsl(120, 100%, 40%);">+ enum osmo_tray_sync_pat_id sync_pat_id;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* In order to determine the codec, find the oldest connection on</span><br><span style="color: hsl(120, 100%, 40%);">+      * the endpoint and use its codec information. Normally on an E1</span><br><span style="color: hsl(120, 100%, 40%);">+       * endpoint no more than one connection should exist. */</span><br><span style="color: hsl(120, 100%, 40%);">+      conn = mgcp_conn_get_oldest(endp);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(conn);</span><br><span style="color: hsl(120, 100%, 40%);">+    codec = conn->u.rtp.end.codec;</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(codec);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Update codec information */</span><br><span style="color: hsl(120, 100%, 40%);">+        endp->e1.trau_rtp_st->type =</span><br><span style="color: hsl(120, 100%, 40%);">+        determine_trau_fr_type(codec->subtype_name, endp->e1.scd.rate, endp->e1.last_amr_ft, endp);</span><br><span style="color: hsl(120, 100%, 40%);">+      endp->e1.last_codec = codec;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Update sync pattern */</span><br><span style="color: hsl(120, 100%, 40%);">+     sync_pat_id = determine_trau_sync_pat(codec->subtype_name, endp->e1.scd.rate, endp->e1.last_amr_ft, endp);</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_trau_sync_set_pat(endp->e1.trau_sync_fi, sync_pat_id);</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%);">+/*! Remove E1 resources from endpoint</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] endp endpoint to release. */</span><br><span style="color: hsl(120, 100%, 40%);">+void mgcp_e1_endp_release(struct mgcp_endpoint *endp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGPENDP(endp, DE1, LOGL_DEBUG, "removing I.460 subchannel and sync...\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (endp->e1.schan)</span><br><span style="color: hsl(120, 100%, 40%);">+                osmo_i460_subchan_del(endp->e1.schan);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (endp->e1.trau_rtp_st)</span><br><span style="color: hsl(120, 100%, 40%);">+          talloc_free(endp->e1.trau_rtp_st);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (endp->e1.trau_sync_fi)</span><br><span style="color: hsl(120, 100%, 40%);">+         osmo_fsm_inst_term(endp->e1.trau_sync_fi, OSMO_FSM_TERM_REGULAR, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  memset(&endp->e1, 0, sizeof(endp->e1));</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%);">+/*! Accept RTP message buffer with RTP data and enqueue voice data for E1 transmit.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] endp related endpoint (does not take ownership).</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] codec configuration.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] msg RTP message buffer (including RTP header).</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns 0 on success, -1 on ERROR. */</span><br><span style="color: hsl(120, 100%, 40%);">+int mgcp_e1_send_rtp(struct mgcp_endpoint *endp, struct mgcp_rtp_codec *codec, struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct msgb *msg_tf = msgb_alloc(E1_TRAU_BITS_MSGB, "E1-I.460-TX-TRAU-frame");</span><br><span style="color: hsl(120, 100%, 40%);">+      struct rate_ctr_group *rate_ctrs = endp->trunk->ratectr.e1_stats;</span><br><span style="color: hsl(120, 100%, 40%);">+       unsigned int rtp_hdr_len = sizeof(struct rtp_hdr);</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_trau_frame tf;</span><br><span style="color: hsl(120, 100%, 40%);">+    uint8_t amr_ft;</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Extract AMR frame type from AMR head (if AMR is used) */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (tf_type_is_amr(endp->e1.trau_rtp_st->type))</span><br><span style="color: hsl(120, 100%, 40%);">+         amr_ft = (msgb_data(msg)[rtp_hdr_len + 1] >> 3) & 0xf;</span><br><span style="color: hsl(120, 100%, 40%);">+      else</span><br><span style="color: hsl(120, 100%, 40%);">+          amr_ft = 0xff;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Adapt TRAU frame type on codec changes */</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(endp->e1.last_codec);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (codec != endp->e1.last_codec || (amr_ft != 0xff && amr_ft != endp->e1.last_amr_ft)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               endp->e1.trau_rtp_st->type =</span><br><span style="color: hsl(120, 100%, 40%);">+                determine_trau_fr_type(codec->subtype_name, endp->e1.scd.rate, amr_ft, endp);</span><br><span style="color: hsl(120, 100%, 40%);">+               endp->e1.last_codec = codec;</span><br><span style="color: hsl(120, 100%, 40%);">+               endp->e1.last_amr_ft = amr_ft;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (endp->e1.trau_rtp_st->type == OSMO_TRAU_FT_NONE)</span><br><span style="color: hsl(120, 100%, 40%);">+            goto skip;</span><br><span style="color: hsl(120, 100%, 40%);">+    LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-TX: using trau frame type for encoding: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+             osmo_trau_frame_type_name(endp->e1.trau_rtp_st->type));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Convert from RTP to TRAU format */</span><br><span style="color: hsl(120, 100%, 40%);">+ msg->l2h = msgb_data(msg) + rtp_hdr_len;</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-TX: decoding %u bytes of RTP audio to TRAU format: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+          msgb_length(msg), osmo_hexdump(msgb_l2(msg), msgb_l2len(msg)));</span><br><span style="color: hsl(120, 100%, 40%);">+      memset(&tf, 0, sizeof(tf));</span><br><span style="color: hsl(120, 100%, 40%);">+       tf.dir = OSMO_TRAU_DIR_DL;</span><br><span style="color: hsl(120, 100%, 40%);">+    rc = osmo_rtp2trau(&tf, msgb_l2(msg), msgb_l2len(msg), endp->e1.trau_rtp_st);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGPENDP(endp, DE1, LOGL_DEBUG,</span><br><span style="color: hsl(120, 100%, 40%);">+                        "E1-I.460-TX: failed to decode from RTP payload format to TRAU format\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         goto skip;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     rc = osmo_trau_frame_encode(msgb_data(msg_tf), msg_tf->data_len, &tf);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-TX: failed to encode TRAU frame\n");</span><br><span style="color: hsl(120, 100%, 40%);">+              goto skip;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_put(msg_tf, rc);</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-TX: enquing %u trau frame bits: %s...\n", msgb_length(msg_tf),</span><br><span style="color: hsl(120, 100%, 40%);">+             osmo_ubit_dump(msgb_data(msg_tf),</span><br><span style="color: hsl(120, 100%, 40%);">+                            msgb_length(msg_tf) > DEBUG_BITS_MAX ? DEBUG_BITS_MAX : msgb_length(msg_tf)));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Enqueue data to I.460 multiplexer */</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(endp->e1.schan);</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(endp->e1.trau_sync_fi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_i460_mux_enqueue(endp->e1.schan, msg_tf);</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-TX: %u bits of audio enqued for E1 tx\n", msgb_length(msg_tf));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+skip:</span><br><span style="color: hsl(120, 100%, 40%);">+      rate_ctr_inc(&rate_ctrs->ctr[E1_I460_TRAU_TX_FAIL_CTR]);</span><br><span style="color: hsl(120, 100%, 40%);">+       msgb_free(msg_tf);</span><br><span style="color: hsl(120, 100%, 40%);">+    return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/libosmo-mgcp/mgcp_endp.c b/src/libosmo-mgcp/mgcp_endp.c</span><br><span>index 5d9ec27..f0ad0a7 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,33 +25,12 @@</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%);">+#include <osmocom/mgcp/mgcp_e1.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #define E1_TIMESLOTS 32</span><br><span> #define E1_RATE_MAX 64</span><br><span> #define E1_OFFS_MAX 8</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 subslots is not possible there is a limited</span><br><span style="color: hsl(0, 100%, 40%);">- * set of subslot assignments possible. The e1_rates array lists the possible</span><br><span style="color: hsl(0, 100%, 40%);">- * assignments as depicted above. Also each subslot assignment comes along with</span><br><span style="color: hsl(0, 100%, 40%);">- * a bit offset in the E1 bitstream. The e1_offsets arrays lists the bit</span><br><span style="color: hsl(0, 100%, 40%);">- * offsets. */</span><br><span style="color: hsl(0, 100%, 40%);">-static const uint8_t e1_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 e1_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 style="color: hsl(0, 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>@@ -116,7 +95,7 @@</span><br><span>              endp->name = gen_virtual_epname(endp, trunk->cfg->domain, index);</span><br><span>           break;</span><br><span>       case MGCP_TRUNK_E1:</span><br><span style="color: hsl(0, 100%, 40%);">-             endp->type = &ep_typeset.rtp;</span><br><span style="color: hsl(120, 100%, 40%);">+          endp->type = &ep_typeset.e1;</span><br><span>          endp->name = gen_e1_epname(endp, trunk->cfg->domain,</span><br><span>                                           trunk->trunk_nr,</span><br><span>                                          index / MGCP_ENDP_E1_SUBSLOTS, index % MGCP_ENDP_E1_SUBSLOTS);</span><br><span>@@ -149,6 +128,9 @@</span><br><span>      talloc_free(endp->local_options.codec);</span><br><span>   endp->local_options.codec = NULL;</span><br><span>         endp->wildcarded_req = false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (endp->trunk->trunk_type == MGCP_TRUNK_E1)</span><br><span style="color: hsl(120, 100%, 40%);">+           mgcp_e1_endp_release(endp);</span><br><span> }</span><br><span> </span><br><span> /* Check if the endpoint name contains the prefix (e.g. "rtpbridge/" or</span><br><span>@@ -614,3 +596,71 @@</span><br><span> </span><br><span>         return false;</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! claim endpoint, sets callid and activates endpoint, should be called at the</span><br><span style="color: hsl(120, 100%, 40%);">+ *  beginning of the CRCX procedure when it is clear that a new call should be</span><br><span style="color: hsl(120, 100%, 40%);">+ *  created.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] endp endpoint to claim.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] callid that is assingned to this endpoint. */</span><br><span style="color: hsl(120, 100%, 40%);">+int mgcp_endp_claim(struct mgcp_endpoint *endp, const char *callid)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t ts;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t ss;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t offs;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* TODO: Make this function more intelligent, it should run the</span><br><span style="color: hsl(120, 100%, 40%);">+        * call id checks we currently have in protocol.c directly here. */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Set the callid, creation of another connection will only be possible</span><br><span style="color: hsl(120, 100%, 40%);">+        * when the callid matches up. (Connections are distinguished by their</span><br><span style="color: hsl(120, 100%, 40%);">+         * connection ids) */</span><br><span style="color: hsl(120, 100%, 40%);">+ endp->callid = talloc_strdup(endp, callid);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(endp->callid);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* Allocate resources */</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%);">+              /* No additional initaliziation required here, virtual</span><br><span style="color: hsl(120, 100%, 40%);">+                 * endpoints will open/close network sockets themselves</span><br><span style="color: hsl(120, 100%, 40%);">+                * on demand. */</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case MGCP_TRUNK_E1:</span><br><span style="color: hsl(120, 100%, 40%);">+           ts = e1_ts_nr_from_epname(endp->name);</span><br><span style="color: hsl(120, 100%, 40%);">+             ss = e1_ss_nr_from_epname(endp->name);</span><br><span style="color: hsl(120, 100%, 40%);">+             offs = e1_offs_from_epname(endp->name);</span><br><span style="color: hsl(120, 100%, 40%);">+            OSMO_ASSERT(ts != 0xFF);</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(ts != 0);</span><br><span style="color: hsl(120, 100%, 40%);">+         OSMO_ASSERT(ss != 0xFF);</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(offs != 0xFF);</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = mgcp_e1_endp_equip(endp, ts, ss, offs);</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</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%);">+   /* Make sure the endpoint is released when claiming the endpoint</span><br><span style="color: hsl(120, 100%, 40%);">+       * failes. */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                mgcp_endp_release(endp);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return rc;</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%);">+/*! update endpoint, updates internal endpoint specific data, should be</span><br><span style="color: hsl(120, 100%, 40%);">+ *  after when MDCX or CRCX has been executed successuflly.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] endp endpoint to update. */</span><br><span style="color: hsl(120, 100%, 40%);">+void mgcp_endp_update(struct mgcp_endpoint *endp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       /* Allocate resources */</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%);">+              /* No updating initaliziation required for virtual endpoints. */</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case MGCP_TRUNK_E1:</span><br><span style="color: hsl(120, 100%, 40%);">+           mgcp_e1_endp_update(endp);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</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>diff --git a/src/libosmo-mgcp/mgcp_network.c b/src/libosmo-mgcp/mgcp_network.c</span><br><span>index 155ed20..e0aa42e 100644</span><br><span>--- a/src/libosmo-mgcp/mgcp_network.c</span><br><span>+++ b/src/libosmo-mgcp/mgcp_network.c</span><br><span>@@ -46,12 +46,11 @@</span><br><span> #include <osmocom/mgcp/mgcp_codec.h></span><br><span> #include <osmocom/mgcp/debug.h></span><br><span> #include <osmocom/codec/codec.h></span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mgcp/mgcp_e1.h></span><br><span> </span><br><span> #define RTP_SEQ_MOD                (1 << 16)</span><br><span> #define RTP_MAX_DROPOUT              3000</span><br><span> #define RTP_MAX_MISORDER        100</span><br><span style="color: hsl(0, 100%, 40%);">-#define RTP_BUF_SIZE         4096</span><br><span> </span><br><span> enum rtp_proto {</span><br><span>         MGCP_PROTO_RTP,</span><br><span>@@ -798,6 +797,23 @@</span><br><span>                    "Forwarding tapped (debug) voice data failed.\n");</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* Generate an RTP header if it is missing */</span><br><span style="color: hsl(120, 100%, 40%);">+static void gen_rtp_header(struct msgb *msg, struct mgcp_rtp_end *rtp_end,</span><br><span style="color: hsl(120, 100%, 40%);">+                    struct mgcp_rtp_state *state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct rtp_hdr *hdr = (struct rtp_hdr *)msgb_data(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (hdr->version > 0)</span><br><span style="color: hsl(120, 100%, 40%);">+           return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     hdr->version = 2;</span><br><span style="color: hsl(120, 100%, 40%);">+  hdr->payload_type = rtp_end->codec->payload_type;</span><br><span style="color: hsl(120, 100%, 40%);">+    hdr->timestamp = osmo_htonl(get_current_ts(rtp_end->codec->rate));</span><br><span style="color: hsl(120, 100%, 40%);">+   hdr->sequence = osmo_htons(state->alt_rtp_tx_sequence);</span><br><span style="color: hsl(120, 100%, 40%);">+ hdr->ssrc = state->alt_rtp_tx_ssrc;</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> /*! Send RTP/RTCP data to a specified destination connection.</span><br><span>  *  \param[in] endp associated endpoint (for configuration, logging).</span><br><span>  *  \param[in] is_rtp flag to specify if the packet is of type RTP or RTCP.</span><br><span>@@ -857,6 +873,11 @@</span><br><span>     rtp_state = &conn_src->state;</span><br><span>         dest_name = conn_dst->conn->name;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+   /* Ensure we have an alternative SSRC in case we need it, see also</span><br><span style="color: hsl(120, 100%, 40%);">+     * gen_rtp_header() */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (rtp_state->alt_rtp_tx_ssrc == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+               rtp_state->alt_rtp_tx_ssrc = rand();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>    if (!rtp_end->output_enabled) {</span><br><span>           rtpconn_rate_ctr_inc(conn_dst, endp, RTP_DROPPED_PACKETS_CTR);</span><br><span>               LOGPENDP(endp, DRTP, LOGL_DEBUG,</span><br><span>@@ -870,6 +891,11 @@</span><br><span>              int cont;</span><br><span>            int nbytes = 0;</span><br><span>              int buflen = msgb_length(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              /* Make sure we have a valid RTP header, in cases where no RTP</span><br><span style="color: hsl(120, 100%, 40%);">+                 * header is present, we will generate one. */</span><br><span style="color: hsl(120, 100%, 40%);">+                gen_rtp_header(msg, rtp_end, rtp_state);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>           do {</span><br><span>                         /* Run transcoder */</span><br><span>                         cont = endp->cfg->rtp_processing_cb(endp, rtp_end,</span><br><span>@@ -938,6 +964,7 @@</span><br><span> </span><br><span>                   rtpconn_rate_ctr_inc(conn_dst, endp, RTP_PACKETS_TX_CTR);</span><br><span>                    rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);</span><br><span style="color: hsl(120, 100%, 40%);">+                 rtp_state->alt_rtp_tx_sequence++;</span><br><span> </span><br><span>                     nbytes += len;</span><br><span>                       buflen = cont;</span><br><span>@@ -956,6 +983,7 @@</span><br><span> </span><br><span>             rtpconn_rate_ctr_inc(conn_dst, endp, RTP_PACKETS_TX_CTR);</span><br><span>            rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);</span><br><span style="color: hsl(120, 100%, 40%);">+         rtp_state->alt_rtp_tx_sequence++;</span><br><span> </span><br><span>             return len;</span><br><span>  }</span><br><span>@@ -1236,12 +1264,24 @@</span><br><span>  struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg);</span><br><span>         struct mgcp_conn_rtp *conn_src = mc->conn_src;</span><br><span>    struct mgcp_conn *conn = conn_src->conn;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct sockaddr_in *from_addr = mc->from_addr;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* FIXME: integrate E1 support from libsomoabis, also implement</span><br><span style="color: hsl(0, 100%, 40%);">-  * handling for RTCP packets, which can not converted to E1. */</span><br><span style="color: hsl(0, 100%, 40%);">- LOGPCONN(conn, DRTP, LOGL_FATAL,</span><br><span style="color: hsl(0, 100%, 40%);">-                 "cannot dispatch! E1 support is not implemented yet!\n");</span><br><span style="color: hsl(0, 100%, 40%);">-    return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Check if the connection is in loopback mode, if yes, just send the</span><br><span style="color: hsl(120, 100%, 40%);">+  * incoming data back to the origin */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (conn->mode == MGCP_CONN_LOOPBACK) {</span><br><span style="color: hsl(120, 100%, 40%);">+            /* When we are in loopback mode, we loop back all incoming</span><br><span style="color: hsl(120, 100%, 40%);">+             * packets back to their origin. We will use the originating</span><br><span style="color: hsl(120, 100%, 40%);">+           * address data from the UDP packet header to patch the</span><br><span style="color: hsl(120, 100%, 40%);">+                * outgoing address in connection on the fly */</span><br><span style="color: hsl(120, 100%, 40%);">+               if (conn->u.rtp.end.rtp_port == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       conn->u.rtp.end.addr = from_addr->sin_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+                     conn->u.rtp.end.rtp_port = from_addr->sin_port;</span><br><span style="color: hsl(120, 100%, 40%);">+         }</span><br><span style="color: hsl(120, 100%, 40%);">+             return mgcp_send_rtp(conn_src, msg);</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%);">+   /* Forward to E1 */</span><br><span style="color: hsl(120, 100%, 40%);">+   return mgcp_e1_send_rtp(conn->endp, conn->u.rtp.end.codec, msg);</span><br><span> }</span><br><span> </span><br><span> /*! cleanup an endpoint when a connection on an RTP bridge endpoint is removed.</span><br><span>@@ -1267,8 +1307,9 @@</span><br><span>  *  \param[in] conn Connection that is about to be removed (ignored). */</span><br><span> void mgcp_cleanup_e1_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-       LOGPCONN(conn, DRTP, LOGL_FATAL,</span><br><span style="color: hsl(0, 100%, 40%);">-                 "cannot dispatch! E1 support is not implemented yet!\n");</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Cleanup tasks for E1 are the same as for regular endpoint. The</span><br><span style="color: hsl(120, 100%, 40%);">+      * shut down of the E1 part is handled separately. */</span><br><span style="color: hsl(120, 100%, 40%);">+ mgcp_cleanup_rtp_bridge_cb(endp, conn);</span><br><span> }</span><br><span> </span><br><span> static bool is_dummy_msg(enum rtp_proto proto, struct msgb *msg)</span><br><span>diff --git a/src/libosmo-mgcp/mgcp_protocol.c b/src/libosmo-mgcp/mgcp_protocol.c</span><br><span>index bc96462..2a6581e 100644</span><br><span>--- a/src/libosmo-mgcp/mgcp_protocol.c</span><br><span>+++ b/src/libosmo-mgcp/mgcp_protocol.c</span><br><span>@@ -849,10 +849,16 @@</span><br><span>            }</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* Set the callid, creation of another connection will only be possible</span><br><span style="color: hsl(0, 100%, 40%);">-  * when the callid matches up. (Connections are distinguished by their</span><br><span style="color: hsl(0, 100%, 40%);">-   * connection ids) */</span><br><span style="color: hsl(0, 100%, 40%);">-   endp->callid = talloc_strdup(trunk->endpoints, callid);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!endp->callid) {</span><br><span style="color: hsl(120, 100%, 40%);">+               /* Claim endpoint resources. This will also set the callid,</span><br><span style="color: hsl(120, 100%, 40%);">+            * creating additional connections will only be possible if</span><br><span style="color: hsl(120, 100%, 40%);">+            * the callid matches up (see above). */</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = mgcp_endp_claim(endp, callid);</span><br><span style="color: hsl(120, 100%, 40%);">+           if (rc != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_FAIL_CLAIM]);</span><br><span style="color: hsl(120, 100%, 40%);">+                   return create_err_response(endp, 502, "CRCX", p->trans);</span><br><span style="color: hsl(120, 100%, 40%);">+         }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span> </span><br><span>        snprintf(conn_name, sizeof(conn_name), "%s", callid);</span><br><span>      _conn = mgcp_conn_alloc(trunk->endpoints, endp, MGCP_CONN_TYPE_RTP, conn_name);</span><br><span>@@ -863,6 +869,7 @@</span><br><span>             goto error2;</span><br><span> </span><br><span>     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  conn = mgcp_conn_get_rtp(endp, _conn->id);</span><br><span>        OSMO_ASSERT(conn);</span><br><span> </span><br><span>@@ -979,6 +986,7 @@</span><br><span>         LOGPCONN(_conn, DLMGCP, LOGL_NOTICE,</span><br><span>                  "CRCX: connection successfully created\n");</span><br><span>       rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_SUCCESS]);</span><br><span style="color: hsl(120, 100%, 40%);">+      mgcp_endp_update(endp);</span><br><span>      return create_response_with_sdp(endp, conn, "CRCX", p->trans, true);</span><br><span> error2:</span><br><span>         mgcp_endp_release(endp);</span><br><span>@@ -1206,6 +1214,7 @@</span><br><span> </span><br><span>         LOGPCONN(conn->conn, DLMGCP, LOGL_NOTICE,</span><br><span>                  "MDCX: connection successfully modified\n");</span><br><span style="color: hsl(120, 100%, 40%);">+       mgcp_endp_update(endp);</span><br><span>      return create_response_with_sdp(endp, conn, "MDCX", p->trans, false);</span><br><span> error3:</span><br><span>        return create_err_response(endp, error_code, "MDCX", p->trans);</span><br><span>diff --git a/src/libosmo-mgcp/mgcp_ratectr.c b/src/libosmo-mgcp/mgcp_ratectr.c</span><br><span>index 1a89c83..aacdd85 100644</span><br><span>--- a/src/libosmo-mgcp/mgcp_ratectr.c</span><br><span>+++ b/src/libosmo-mgcp/mgcp_ratectr.c</span><br><span>@@ -64,6 +64,7 @@</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>         [MGCP_CRCX_FAIL_AVAIL] = { "crcx:unavailable", "endpoint unavailable." },</span><br><span style="color: hsl(120, 100%, 40%);">+ [MGCP_CRCX_FAIL_CLAIM] = { "crcx:claim", "endpoint can not be claimed." },</span><br><span> };</span><br><span> </span><br><span> const static struct rate_ctr_group_desc mgcp_crcx_ctr_group_desc = {</span><br><span>@@ -124,6 +125,20 @@</span><br><span>      .ctr_desc = mgcp_dlcx_ctr_desc</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static const struct rate_ctr_desc e1_rate_ctr_desc[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+    [E1_I460_TRAU_RX_FAIL_CTR] = {"e1:rx_fail", "Inbound I.460 TRAU failures."},</span><br><span style="color: hsl(120, 100%, 40%);">+      [E1_I460_TRAU_TX_FAIL_CTR] = {"e1:tx_fail", "Outbound I.460 TRAU failures."},</span><br><span style="color: hsl(120, 100%, 40%);">+     [E1_I460_TRAU_MUX_EMPTY_CTR] = {"e1:i460", "Outbound I.460 MUX queue empty."}</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%);">+const static struct rate_ctr_group_desc e1_rate_ctr_group_desc = {</span><br><span style="color: hsl(120, 100%, 40%);">+   .group_name_prefix = "e1",</span><br><span style="color: hsl(120, 100%, 40%);">+  .group_description = "e1 statistics",</span><br><span style="color: hsl(120, 100%, 40%);">+       .class_id = OSMO_STATS_CLASS_GLOBAL,</span><br><span style="color: hsl(120, 100%, 40%);">+  .num_ctr = ARRAY_SIZE(e1_rate_ctr_desc),</span><br><span style="color: hsl(120, 100%, 40%);">+      .ctr_desc = e1_rate_ctr_desc</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> const static struct rate_ctr_group_desc all_rtp_conn_rate_ctr_group_desc = {</span><br><span>   .group_name_prefix = "all_rtp_conn",</span><br><span>       .group_description = "aggregated statistics for all rtp connections",</span><br><span>@@ -203,5 +218,12 @@</span><br><span>               talloc_set_destructor(ratectr->all_rtp_conn_stats, free_rate_counter_group);</span><br><span>              all_rtp_conn_rate_ctr_index++;</span><br><span>       }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (ratectr->e1_stats == NULL) {</span><br><span style="color: hsl(120, 100%, 40%);">+           ratectr->e1_stats = rate_ctr_group_alloc(ctx, &e1_rate_ctr_group_desc, mdcx_rate_ctr_index);</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!ratectr->e1_stats)</span><br><span style="color: hsl(120, 100%, 40%);">+                    return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+               talloc_set_destructor(ratectr->e1_stats, free_rate_counter_group);</span><br><span style="color: hsl(120, 100%, 40%);">+         mdcx_rate_ctr_index++;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span>    return 0;</span><br><span> }</span><br><span>diff --git a/src/libosmo-mgcp/mgcp_trunk.c b/src/libosmo-mgcp/mgcp_trunk.c</span><br><span>index 0d7b385..dfedc4b 100644</span><br><span>--- a/src/libosmo-mgcp/mgcp_trunk.c</span><br><span>+++ b/src/libosmo-mgcp/mgcp_trunk.c</span><br><span>@@ -24,6 +24,8 @@</span><br><span> #include <osmocom/mgcp/mgcp_internal.h></span><br><span> #include <osmocom/mgcp/mgcp_endp.h></span><br><span> #include <osmocom/mgcp/mgcp_trunk.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mgcp/mgcp_e1.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/abis/e1_input.h></span><br><span> </span><br><span> /*! allocate trunk and add it (if required) to the trunk list.</span><br><span>  *  (called once at startup by VTY).</span><br><span>@@ -47,7 +49,7 @@</span><br><span> </span><br><span>     trunk->audio_send_ptime = 1;</span><br><span>      trunk->audio_send_name = 1;</span><br><span style="color: hsl(0, 100%, 40%);">-  trunk->vty_number_endpoints = 32;</span><br><span style="color: hsl(120, 100%, 40%);">+  trunk->v.vty_number_endpoints = 32;</span><br><span>       trunk->omit_rtcp = 0;</span><br><span> </span><br><span>         mgcp_trunk_set_keepalive(trunk, MGCP_KEEPALIVE_ONCE);</span><br><span>@@ -81,13 +83,13 @@</span><br><span>          /* Due to historical reasons the endpoints on the virtual</span><br><span>             * trunk start counting at 1. */</span><br><span>             first_endpoint_nr = 1;</span><br><span style="color: hsl(0, 100%, 40%);">-          number_endpoints = trunk->vty_number_endpoints;</span><br><span style="color: hsl(120, 100%, 40%);">+            number_endpoints = trunk->v.vty_number_endpoints;</span><br><span>                 break;</span><br><span>       case MGCP_TRUNK_E1:</span><br><span>          /* The first timeslot on an E1 line is reserved for framing</span><br><span>           * and alignment and can not be used for audio transport */</span><br><span>          first_endpoint_nr = 1 * MGCP_ENDP_E1_SUBSLOTS;</span><br><span style="color: hsl(0, 100%, 40%);">-          number_endpoints = 31 * MGCP_ENDP_E1_SUBSLOTS;</span><br><span style="color: hsl(120, 100%, 40%);">+                number_endpoints = (NUM_E1_TS-1) * MGCP_ENDP_E1_SUBSLOTS;</span><br><span>            break;</span><br><span>       default:</span><br><span>             OSMO_ASSERT(false);</span><br><span>@@ -122,6 +124,41 @@</span><br><span>   return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! Equip trunk with endpoints and resources</span><br><span style="color: hsl(120, 100%, 40%);">+ *  (called once at startup by VTY).</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] trunk trunk configuration.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns 0 on success, -1 on failure. */</span><br><span style="color: hsl(120, 100%, 40%);">+int mgcp_trunk_equip(struct mgcp_trunk *trunk)</span><br><span style="color: hsl(120, 100%, 40%);">+{</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%);">+     /* Allocate endpoints */</span><br><span style="color: hsl(120, 100%, 40%);">+      if(mgcp_trunk_alloc_endpts(trunk) != 0)</span><br><span style="color: hsl(120, 100%, 40%);">+               return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Allocate resources */</span><br><span style="color: hsl(120, 100%, 40%);">+      switch (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%);">+              /* No additional initaliziation required here, virtual</span><br><span style="color: hsl(120, 100%, 40%);">+                 * endpoints will open/close network sockets themselves</span><br><span style="color: hsl(120, 100%, 40%);">+                * on demand. */</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case MGCP_TRUNK_E1:</span><br><span style="color: hsl(120, 100%, 40%);">+           /* The TS initalization happens once on startup for all</span><br><span style="color: hsl(120, 100%, 40%);">+                * timeslots. This only affects the i460 multiplexer. Until</span><br><span style="color: hsl(120, 100%, 40%);">+            * now no E1 resources are claimed yet. This happens on demand</span><br><span style="color: hsl(120, 100%, 40%);">+                 * when the related endpoint is actually used */</span><br><span style="color: hsl(120, 100%, 40%);">+              memset(trunk->e1.i460_ts, 0, sizeof(trunk->e1.i460_ts));</span><br><span style="color: hsl(120, 100%, 40%);">+                for (i = 0; i < (NUM_E1_TS-1); i++)</span><br><span style="color: hsl(120, 100%, 40%);">+                        osmo_i460_ts_init(&trunk->e1.i460_ts[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</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 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! get trunk configuration by trunk number (index).</span><br><span>  *  \param[in] cfg mgcp configuration.</span><br><span>  *  \param[in] ttype trunk type.</span><br><span>@@ -199,3 +236,19 @@</span><br><span>  LOGP(DLMGCP, LOGL_ERROR, "unable to find trunk for endpoint name \"%s\"!\n", epname);</span><br><span>    return NULL;</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Find a trunk (E1) by its associated E1 line number.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] num e1 line number.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns trunk or NULL if trunk was not found. */</span><br><span style="color: hsl(120, 100%, 40%);">+struct mgcp_trunk *mgcp_trunk_by_line_num(const struct mgcp_config *cfg, unsigned int num)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        /*! When used on trunks other than E1, the result will always be NULL. */</span><br><span style="color: hsl(120, 100%, 40%);">+     struct mgcp_trunk *trunk;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   llist_for_each_entry(trunk, &cfg->trunks, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+             if (trunk->trunk_type == MGCP_TRUNK_E1 && trunk->e1.vty_line_nr == num)</span><br><span style="color: hsl(120, 100%, 40%);">+                 return trunk;</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 NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/libosmo-mgcp/mgcp_vty.c b/src/libosmo-mgcp/mgcp_vty.c</span><br><span>index 35b75fb..b8ec241 100644</span><br><span>--- a/src/libosmo-mgcp/mgcp_vty.c</span><br><span>+++ b/src/libosmo-mgcp/mgcp_vty.c</span><br><span>@@ -112,7 +112,7 @@</span><br><span>               trunk->audio_send_name ? "" : "no ", VTY_NEWLINE);</span><br><span>    vty_out(vty, " loop %u%s", ! !trunk->audio_loop, VTY_NEWLINE);</span><br><span>  vty_out(vty, " number endpoints %u%s",</span><br><span style="color: hsl(0, 100%, 40%);">-                trunk->vty_number_endpoints, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+         trunk->v.vty_number_endpoints, VTY_NEWLINE);</span><br><span>      vty_out(vty, " %sallow-transcoding%s",</span><br><span>             trunk->no_audio_transcoding ? "no " : "", VTY_NEWLINE);</span><br><span>       if (g_cfg->call_agent_addr)</span><br><span>@@ -243,8 +243,10 @@</span><br><span>        }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static void dump_ratectr_trunk(struct vty *vty, struct mgcp_ratectr_trunk *ratectr)</span><br><span style="color: hsl(120, 100%, 40%);">+static void dump_ratectr_trunk(struct vty *vty, struct mgcp_trunk *trunk)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct mgcp_ratectr_trunk *ratectr = &trunk->ratectr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>       vty_out(vty, "%s", VTY_NEWLINE);</span><br><span>   vty_out(vty, "Rate counters (trunk):%s", VTY_NEWLINE);</span><br><span> </span><br><span>@@ -280,6 +282,15 @@</span><br><span>                                     "   %25n: %10c (%S/s %M/m %H/h %D/d) %d",</span><br><span>                                          ratectr->all_rtp_conn_stats);</span><br><span>  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (ratectr->e1_stats && trunk->trunk_type == MGCP_TRUNK_E1) {</span><br><span style="color: hsl(120, 100%, 40%);">+          vty_out(vty, "   %s:%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                    ratectr->e1_stats->desc->group_description,</span><br><span style="color: hsl(120, 100%, 40%);">+                  VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+         vty_out_rate_ctr_group_fmt(vty,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          "   %25n: %10c (%S/s %M/m %H/h %D/d) %d",</span><br><span style="color: hsl(120, 100%, 40%);">+                                           ratectr->e1_stats);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span> }</span><br><span> </span><br><span> </span><br><span>@@ -305,7 +316,7 @@</span><br><span>         }</span><br><span> </span><br><span>        if (show_stats)</span><br><span style="color: hsl(0, 100%, 40%);">-         dump_ratectr_trunk(vty, &trunk->ratectr);</span><br><span style="color: hsl(120, 100%, 40%);">+              dump_ratectr_trunk(vty, trunk);</span><br><span> }</span><br><span> </span><br><span> #define SHOW_MGCP_STR "Display information about the MGCP Media Gateway\n"</span><br><span>@@ -715,7 +726,7 @@</span><br><span> {</span><br><span>  struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);</span><br><span>         OSMO_ASSERT(trunk);</span><br><span style="color: hsl(0, 100%, 40%);">-     trunk->vty_number_endpoints = atoi(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+       trunk->v.vty_number_endpoints = atoi(argv[0]);</span><br><span>    return CMD_SUCCESS;</span><br><span> }</span><br><span> </span><br><span>@@ -894,6 +905,7 @@</span><br><span>                   continue;</span><br><span> </span><br><span>                vty_out(vty, " trunk %d%s", trunk->trunk_nr, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+               vty_out(vty, "  line %u%s", trunk->e1.vty_line_nr, VTY_NEWLINE);</span><br><span>                vty_out(vty, "  %ssdp audio-payload send-ptime%s",</span><br><span>                         trunk->audio_send_ptime ? "" : "no ", VTY_NEWLINE);</span><br><span>           vty_out(vty, "  %ssdp audio-payload send-name%s",</span><br><span>@@ -1159,6 +1171,19 @@</span><br><span>         return CMD_SUCCESS;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#define LINE_STR "Configure trunk for given Line\nE1/T1 Line Number\n"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_trunk_line,</span><br><span style="color: hsl(120, 100%, 40%);">+      cfg_trunk_line_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "line <0-255>",</span><br><span style="color: hsl(120, 100%, 40%);">+      LINE_STR)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct mgcp_trunk *trunk = vty->index;</span><br><span style="color: hsl(120, 100%, 40%);">+     int line_nr = atoi(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+  trunk->e1.vty_line_nr = line_nr;</span><br><span style="color: hsl(120, 100%, 40%);">+   return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> DEFUN(loop_conn,</span><br><span>       loop_conn_cmd,</span><br><span>       "loop-endpoint <0-64> NAME (0|1)",</span><br><span>@@ -1549,6 +1574,7 @@</span><br><span>     install_element(TRUNK_NODE, &cfg_trunk_no_sdp_payload_send_name_cmd);</span><br><span>    install_element(TRUNK_NODE, &cfg_trunk_allow_transcoding_cmd);</span><br><span>   install_element(TRUNK_NODE, &cfg_trunk_no_allow_transcoding_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+ install_element(TRUNK_NODE, &cfg_trunk_line_cmd);</span><br><span> </span><br><span>    return 0;</span><br><span> }</span><br><span>@@ -1577,7 +1603,7 @@</span><br><span>       }</span><br><span> </span><br><span>        llist_for_each_entry(trunk, &g_cfg->trunks, entry) {</span><br><span style="color: hsl(0, 100%, 40%);">-             if (mgcp_trunk_alloc_endpts(trunk) != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+            if (mgcp_trunk_equip(trunk) != 0) {</span><br><span>                  LOGP(DLMGCP, LOGL_ERROR,</span><br><span>                          "Failed to initialize trunk %d (%d endpoints)\n",</span><br><span>                          trunk->trunk_nr, trunk->number_endpoints);</span><br><span>diff --git a/src/osmo-mgw/Makefile.am b/src/osmo-mgw/Makefile.am</span><br><span>index d38df9f..928390b 100644</span><br><span>--- a/src/osmo-mgw/Makefile.am</span><br><span>+++ b/src/osmo-mgw/Makefile.am</span><br><span>@@ -11,6 +11,8 @@</span><br><span>       $(LIBOSMOGSM_CFLAGS) \</span><br><span>       $(LIBOSMOCTRL_CFLAGS) \</span><br><span>      $(LIBOSMONETIF_CFLAGS) \</span><br><span style="color: hsl(120, 100%, 40%);">+      $(LIBOSMOABIS_CFLAGS) \</span><br><span style="color: hsl(120, 100%, 40%);">+       $(LIBOSMOTRAU_CFLAGS) \</span><br><span>      $(COVERAGE_CFLAGS) \</span><br><span>         $(NULL)</span><br><span> </span><br><span>@@ -29,4 +31,6 @@</span><br><span>      $(LIBOSMOGSM_LIBS) \</span><br><span>         $(LIBOSMOCTRL_LIBS) \</span><br><span>        $(LIBOSMONETIF_LIBS) \</span><br><span style="color: hsl(120, 100%, 40%);">+        $(LIBOSMOABIS_LIBS) \</span><br><span style="color: hsl(120, 100%, 40%);">+ $(LIBOSMOTRAU_LIBS) \</span><br><span>        $(NULL)</span><br><span>diff --git a/src/osmo-mgw/mgw_main.c b/src/osmo-mgw/mgw_main.c</span><br><span>index 6ca1800..036e0c0 100644</span><br><span>--- a/src/osmo-mgw/mgw_main.c</span><br><span>+++ b/src/osmo-mgw/mgw_main.c</span><br><span>@@ -30,6 +30,8 @@</span><br><span> #include <limits.h></span><br><span> #include <unistd.h></span><br><span> #include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/msgb.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/abis/e1_input.h></span><br><span> </span><br><span> #include <sys/socket.h></span><br><span> </span><br><span>@@ -58,6 +60,7 @@</span><br><span> #include <osmocom/vty/command.h></span><br><span> #include <osmocom/vty/stats.h></span><br><span> #include <osmocom/vty/misc.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/abis/abis.h></span><br><span> </span><br><span> #include "../../bscconfig.h"</span><br><span> </span><br><span>@@ -268,7 +271,13 @@</span><br><span>                .description = "RTP stream handling",</span><br><span>              .color = "\033[1;30m",</span><br><span>             .enabled = 1,.loglevel = LOGL_NOTICE,</span><br><span style="color: hsl(0, 100%, 40%);">-           },</span><br><span style="color: hsl(120, 100%, 40%);">+  },</span><br><span style="color: hsl(120, 100%, 40%);">+    [DE1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+               .name = "DE1",</span><br><span style="color: hsl(120, 100%, 40%);">+              .description = "E1 line handling",</span><br><span style="color: hsl(120, 100%, 40%);">+                  .color = "\033[1;31m",</span><br><span style="color: hsl(120, 100%, 40%);">+              .enabled = 1,.loglevel = LOGL_NOTICE,</span><br><span style="color: hsl(120, 100%, 40%);">+       },</span><br><span> };</span><br><span> </span><br><span> const struct log_info log_info = {</span><br><span>@@ -288,6 +297,7 @@</span><br><span> </span><br><span>         osmo_init_ignore_signals();</span><br><span>  osmo_init_logging2(tall_bsc_ctx, &log_info);</span><br><span style="color: hsl(120, 100%, 40%);">+      libosmo_abis_init(tall_bsc_ctx);</span><br><span> </span><br><span>         cfg = mgcp_config_alloc();</span><br><span>   if (!cfg)</span><br><span>@@ -300,6 +310,7 @@</span><br><span>      osmo_stats_vty_add_cmds();</span><br><span>   mgcp_vty_init();</span><br><span>     ctrl_vty_init(cfg);</span><br><span style="color: hsl(120, 100%, 40%);">+   e1inp_vty_init();</span><br><span> </span><br><span>        handle_options(argc, argv);</span><br><span> </span><br><span>diff --git a/tests/mgcp/Makefile.am b/tests/mgcp/Makefile.am</span><br><span>index 95444b5..1224c0a 100644</span><br><span>--- a/tests/mgcp/Makefile.am</span><br><span>+++ b/tests/mgcp/Makefile.am</span><br><span>@@ -11,6 +11,8 @@</span><br><span>     $(LIBOSMOVTY_CFLAGS) \</span><br><span>       $(LIBOSMOGSM_CFLAGS) \</span><br><span>       $(LIBOSMONETIF_CFLAGS) \</span><br><span style="color: hsl(120, 100%, 40%);">+      $(LIBOSMOABIS_CFLAGS) \</span><br><span style="color: hsl(120, 100%, 40%);">+       $(LIBOSMOTRAU_CFLAGS) \</span><br><span>      $(COVERAGE_CFLAGS) \</span><br><span>         $(NULL)</span><br><span> </span><br><span>@@ -35,6 +37,8 @@</span><br><span>      $(LIBOSMOCORE_LIBS) \</span><br><span>        $(LIBOSMOVTY_LIBS) \</span><br><span>         $(LIBOSMOGSM_LIBS) \</span><br><span style="color: hsl(120, 100%, 40%);">+  $(LIBOSMOABIS_LIBS) \</span><br><span style="color: hsl(120, 100%, 40%);">+ $(LIBOSMOTRAU_LIBS) \</span><br><span>        $(LIBRARY_DL) \</span><br><span>      $(LIBRARY_DLSYM) \</span><br><span>   $(LIBOSMONETIF_LIBS) \</span><br><span>diff --git a/tests/mgcp/mgcp_test.c b/tests/mgcp/mgcp_test.c</span><br><span>index 458f6c9..a050a0b 100644</span><br><span>--- a/tests/mgcp/mgcp_test.c</span><br><span>+++ b/tests/mgcp/mgcp_test.c</span><br><span>@@ -771,8 +771,8 @@</span><br><span>    cfg = mgcp_config_alloc();</span><br><span>   trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     trunk->vty_number_endpoints = 64;</span><br><span style="color: hsl(0, 100%, 40%);">-        mgcp_trunk_alloc_endpts(trunk);</span><br><span style="color: hsl(120, 100%, 40%);">+   trunk->v.vty_number_endpoints = 64;</span><br><span style="color: hsl(120, 100%, 40%);">+        mgcp_trunk_equip(trunk);</span><br><span>     cfg->policy_cb = mgcp_test_policy_cb;</span><br><span> </span><br><span>         memset(last_conn_id, 0, sizeof(last_conn_id));</span><br><span>@@ -908,8 +908,8 @@</span><br><span>         cfg = mgcp_config_alloc();</span><br><span>   trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     trunk->vty_number_endpoints = 64;</span><br><span style="color: hsl(0, 100%, 40%);">-        mgcp_trunk_alloc_endpts(trunk);</span><br><span style="color: hsl(120, 100%, 40%);">+   trunk->v.vty_number_endpoints = 64;</span><br><span style="color: hsl(120, 100%, 40%);">+        mgcp_trunk_equip(trunk);</span><br><span> </span><br><span>         memset(last_conn_id, 0, sizeof(last_conn_id));</span><br><span> </span><br><span>@@ -973,8 +973,8 @@</span><br><span>     trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);</span><br><span>      cfg->rqnt_cb = rqnt_cb;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  trunk->vty_number_endpoints = 64;</span><br><span style="color: hsl(0, 100%, 40%);">-        mgcp_trunk_alloc_endpts(trunk);</span><br><span style="color: hsl(120, 100%, 40%);">+   trunk->v.vty_number_endpoints = 64;</span><br><span style="color: hsl(120, 100%, 40%);">+        mgcp_trunk_equip(trunk);</span><br><span> </span><br><span>         inp = create_msg(CRCX, NULL);</span><br><span>        msg = mgcp_handle_message(cfg, inp);</span><br><span>@@ -1050,7 +1050,7 @@</span><br><span> </span><br><span>     endp.cfg = &cfg;</span><br><span>         endp.type = &ep_typeset.rtp;</span><br><span style="color: hsl(0, 100%, 40%);">-        trunk.vty_number_endpoints = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+       trunk.v.vty_number_endpoints = 1;</span><br><span>    trunk.endpoints = endpoints;</span><br><span>         trunk.endpoints[0] = &endp;</span><br><span>      endp.trunk = &trunk;</span><br><span>@@ -1301,7 +1301,7 @@</span><br><span>     endp.cfg = &cfg;</span><br><span>         endp.type = &ep_typeset.rtp;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    trunk.vty_number_endpoints = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+       trunk.v.vty_number_endpoints = 1;</span><br><span>    trunk.endpoints = endpoints;</span><br><span>         trunk.endpoints[0] = &endp;</span><br><span>      trunk.force_constant_ssrc = patch_ssrc;</span><br><span>@@ -1382,8 +1382,8 @@</span><br><span> </span><br><span>  cfg = mgcp_config_alloc();</span><br><span>   trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);</span><br><span style="color: hsl(0, 100%, 40%);">- trunk->vty_number_endpoints = 64;</span><br><span style="color: hsl(0, 100%, 40%);">-        mgcp_trunk_alloc_endpts(trunk);</span><br><span style="color: hsl(120, 100%, 40%);">+   trunk->v.vty_number_endpoints = 64;</span><br><span style="color: hsl(120, 100%, 40%);">+        mgcp_trunk_equip(trunk);</span><br><span>     cfg->policy_cb = mgcp_test_policy_cb;</span><br><span> </span><br><span>         /* Allocate endpoint 1@mgw with two codecs */</span><br><span>@@ -1531,8 +1531,8 @@</span><br><span> </span><br><span>    cfg = mgcp_config_alloc();</span><br><span>   trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);</span><br><span style="color: hsl(0, 100%, 40%);">- trunk->vty_number_endpoints = 64;</span><br><span style="color: hsl(0, 100%, 40%);">-        mgcp_trunk_alloc_endpts(trunk);</span><br><span style="color: hsl(120, 100%, 40%);">+   trunk->v.vty_number_endpoints = 64;</span><br><span style="color: hsl(120, 100%, 40%);">+        mgcp_trunk_equip(trunk);</span><br><span> </span><br><span>         endp = mgcp_endp_by_name(NULL, "rtpbridge/1@mgw", cfg);</span><br><span>    OSMO_ASSERT(endp);</span><br><span>@@ -1581,9 +1581,9 @@</span><br><span>   cfg = mgcp_config_alloc();</span><br><span>   trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     trunk->vty_number_endpoints = 64;</span><br><span style="color: hsl(120, 100%, 40%);">+  trunk->v.vty_number_endpoints = 64;</span><br><span>       trunk->audio_send_name = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-        mgcp_trunk_alloc_endpts(trunk);</span><br><span style="color: hsl(120, 100%, 40%);">+        mgcp_trunk_equip(trunk);</span><br><span> </span><br><span>  cfg->policy_cb = mgcp_test_policy_cb;</span><br><span> </span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-mgw/+/19524">change 19524</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/+/19524"/><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: I6b93809b5ac7d01af55888347dd787b0bc997ae1 </div>
<div style="display:none"> Gerrit-Change-Number: 19524 </div>
<div style="display:none"> Gerrit-PatchSet: 3 </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: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>