<p>neels has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-mgw/+/15169">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">add simplistic IuUP FSM and strip/add IuUP headers<br><br>This should really be using the FSM in libosmocore/laforge/iu_up: take the best<br>of both sides and integate in the libosmocore FSM implementation, then use it<br>here.<br>- in libosmocore, the FSM definition is nicer.<br>- here, we have correct header checksums.<br><br>Introduce using msgb to receive, pass and send RTP packets.<br><br>Add/strip IuUP from RTP data (for which msgb is particularly useful).<br><br>The payload type on an IuUP conn is maintained as negotiated in the IuUP<br>Initialization. For the pure RTP side, an SDP "AMR" ptmap attribute is looked<br>up, so that payload type numbers are translated between IuUP <-> RTP.<br><br>Change-Id: Ibc70e0aa00476926dd1f4ea8139c34f31f9cdfa3<br>---<br>M configure.ac<br>M include/osmocom/mgcp/debug.h<br>A include/osmocom/mgcp/iuup_cn_node.h<br>A include/osmocom/mgcp/iuup_protocol.h<br>M include/osmocom/mgcp/mgcp_codec.h<br>M include/osmocom/mgcp/mgcp_endp.h<br>M include/osmocom/mgcp/mgcp_internal.h<br>M src/libosmo-mgcp/Makefile.am<br>A src/libosmo-mgcp/iuup_cn_node.c<br>A src/libosmo-mgcp/iuup_protocol.c<br>M src/libosmo-mgcp/mgcp_codec.c<br>M src/libosmo-mgcp/mgcp_network.c<br>M src/libosmo-mgcp/mgcp_osmux.c<br>M src/osmo-mgw/mgw_main.c<br>M tests/Makefile.am<br>A tests/iuup/Makefile.am<br>A tests/iuup/iuup_test.c<br>A tests/iuup/iuup_test.err<br>A tests/iuup/iuup_test.ok<br>M tests/mgcp/mgcp_test.c<br>M tests/testsuite.at<br>21 files changed, 1,241 insertions(+), 196 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-mgw refs/changes/69/15169/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/configure.ac b/configure.ac</span><br><span>index 124f1e6..b9e3b60 100644</span><br><span>--- a/configure.ac</span><br><span>+++ b/configure.ac</span><br><span>@@ -195,6 +195,7 @@</span><br><span>     tests/atlocal</span><br><span>     tests/mgcp_client/Makefile</span><br><span>     tests/mgcp/Makefile</span><br><span style="color: hsl(120, 100%, 40%);">+    tests/iuup/Makefile</span><br><span>     doc/Makefile</span><br><span>     doc/examples/Makefile</span><br><span>     doc/manuals/Makefile</span><br><span>diff --git a/include/osmocom/mgcp/debug.h b/include/osmocom/mgcp/debug.h</span><br><span>index ddeb0dc..1eed769 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%);">+ DIUUP,</span><br><span>       Debug_LastEntry,</span><br><span> };</span><br><span> </span><br><span>diff --git a/include/osmocom/mgcp/iuup_cn_node.h b/include/osmocom/mgcp/iuup_cn_node.h</span><br><span>new file mode 100644</span><br><span>index 0000000..ca69b4d</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/mgcp/iuup_cn_node.h</span><br><span>@@ -0,0 +1,47 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */</span><br><span style="color: hsl(120, 100%, 40%);">+/* IuUP CN node, minimal implementation */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*                                            _____IuUP_CN_____</span><br><span style="color: hsl(120, 100%, 40%);">+ *                                            |               |</span><br><span style="color: hsl(120, 100%, 40%);">+ * UE <--> RNC --PDU-> osmo_iuup_cn_rx_pdu() -+->           ---+-> rx_payload()</span><br><span style="color: hsl(120, 100%, 40%);">+ *          |                                 |               |</span><br><span style="color: hsl(120, 100%, 40%);">+ *          |  <-PDU-- tx_msg() <-------------+--           <-+--- osmo_iuup_cn_tx_payload()</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%);">+</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%);">+struct msgb;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+typedef int (*osmo_iuup_data_cb_t)(struct msgb *msg, void *node_priv);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_iuup_cn_cfg {</span><br><span style="color: hsl(120, 100%, 40%);">+      void *node_priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* When the IuUP peer sent a voice packet, the clean RTP without the IuUP header is fed to this</span><br><span style="color: hsl(120, 100%, 40%);">+        * callback. */</span><br><span style="color: hsl(120, 100%, 40%);">+       osmo_iuup_data_cb_t rx_payload;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* IuUP handler requests that a PDU shall be sent to the IuUP peer (e.g. the RNC).</span><br><span style="color: hsl(120, 100%, 40%);">+     * It is guaranteed that the msgb->dst pointer is preserved or copied from the msgb that</span><br><span style="color: hsl(120, 100%, 40%);">+    * originated the request. */</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_iuup_data_cb_t tx_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%);">+struct osmo_iuup_cn {</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_iuup_cn_cfg cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+  char *name;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t next_frame_nr;</span><br><span style="color: hsl(120, 100%, 40%);">+        int rtp_payload_type;</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%);">+bool osmo_iuup_cn_is_iuup_init(struct msgb *msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_iuup_cn *osmo_iuup_cn_init(void *ctx, struct osmo_iuup_cn_cfg *cfg,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    const char *name_fmt, ...);</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_iuup_cn_free(struct osmo_iuup_cn *cn);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_iuup_cn_tx_payload(struct osmo_iuup_cn *cn, struct msgb *payload);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_iuup_cn_rx_pdu(struct osmo_iuup_cn *cn, struct msgb *pdu);</span><br><span>diff --git a/include/osmocom/mgcp/iuup_protocol.h b/include/osmocom/mgcp/iuup_protocol.h</span><br><span>new file mode 100644</span><br><span>index 0000000..f4aec1f</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/mgcp/iuup_protocol.h</span><br><span>@@ -0,0 +1,117 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */</span><br><span style="color: hsl(120, 100%, 40%);">+/* IuUP protocol handling, minimal implementation */</span><br><span style="color: hsl(120, 100%, 40%);">+</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%);">+#include <osmocom/core/endian.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/msgb.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define OSMO_IUUP_HEADROOM 32</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum osmo_iuup_pdu_type {</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_IUUP_PDU_DATA_WITH_CRC = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_IUUP_PDU_CONTROL_PROCEDURE = 14,</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%);">+enum osmo_iuup_acknack {</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_IUUP_ACKNACK_PROCEDURE = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_IUUP_ACKNACK_ACK = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_IUUP_ACKNACK_NACK = 2,</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%);">+enum osmo_iuup_procedure {</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_IUUP_PROC_INITIALIZATION = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_IUUP_PROC_RATE_CONTROL = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_IUUP_PROC_TIME_ALIGNMENT = 2,</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_IUUP_PROC_ERROR_EVENT = 3,</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%);">+enum osmo_iuup_frame_good {</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_IUUP_FRAME_GOOD = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_IUUP_FRAME_BAD = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_IUUP_FRAME_BAD_DUE_TO_RADIO = 2,</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%);">+struct osmo_iuup_hdr_ctrl {</span><br><span style="color: hsl(120, 100%, 40%);">+#if OSMO_IS_BIG_ENDIAN</span><br><span style="color: hsl(120, 100%, 40%);">+      uint8_t pdu_type:4,</span><br><span style="color: hsl(120, 100%, 40%);">+           ack_nack:2,</span><br><span style="color: hsl(120, 100%, 40%);">+           frame_nr:2;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t mode_version:4,</span><br><span style="color: hsl(120, 100%, 40%);">+               procedure:4;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t header_crc:6,</span><br><span style="color: hsl(120, 100%, 40%);">+         payload_crc_hi:2;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint8_t payload_crc_lo;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t payload[0];</span><br><span style="color: hsl(120, 100%, 40%);">+#elif OSMO_IS_LITTLE_ENDIAN</span><br><span style="color: hsl(120, 100%, 40%);">+      uint8_t frame_nr:2,</span><br><span style="color: hsl(120, 100%, 40%);">+           ack_nack:2,</span><br><span style="color: hsl(120, 100%, 40%);">+           pdu_type:4;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t procedure:4,</span><br><span style="color: hsl(120, 100%, 40%);">+          mode_version:4;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t payload_crc_hi:2,</span><br><span style="color: hsl(120, 100%, 40%);">+             header_crc:6;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t payload_crc_lo;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t payload[0];</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+union osmo_iuup_hdr_ctrl_payload {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct {</span><br><span style="color: hsl(120, 100%, 40%);">+#if OSMO_IS_BIG_ENDIAN</span><br><span style="color: hsl(120, 100%, 40%);">+      uint8_t spare:3,</span><br><span style="color: hsl(120, 100%, 40%);">+              iptis_present:1,</span><br><span style="color: hsl(120, 100%, 40%);">+              subflows:3,</span><br><span style="color: hsl(120, 100%, 40%);">+           chain:1;</span><br><span style="color: hsl(120, 100%, 40%);">+#elif OSMO_IS_LITTLE_ENDIAN</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t spare:3,</span><br><span style="color: hsl(120, 100%, 40%);">+              iptis_present:1,</span><br><span style="color: hsl(120, 100%, 40%);">+              subflows:3,</span><br><span style="color: hsl(120, 100%, 40%);">+           chain:1;</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+      } initialization;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   struct {</span><br><span style="color: hsl(120, 100%, 40%);">+#if OSMO_IS_BIG_ENDIAN</span><br><span style="color: hsl(120, 100%, 40%);">+      uint8_t error_distance:2,</span><br><span style="color: hsl(120, 100%, 40%);">+             error_cause:6;</span><br><span style="color: hsl(120, 100%, 40%);">+#elif OSMO_IS_LITTLE_ENDIAN</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t error_cause:6,</span><br><span style="color: hsl(120, 100%, 40%);">+                error_distance:2;</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+     } error_event;</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%);">+extern const struct value_string osmo_iuup_error_cause_names[];</span><br><span style="color: hsl(120, 100%, 40%);">+static inline const char *osmo_iuup_error_cause_name(uint8_t val)</span><br><span style="color: hsl(120, 100%, 40%);">+{ return get_value_string(osmo_iuup_error_cause_names, val); }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_iuup_hdr_data {</span><br><span style="color: hsl(120, 100%, 40%);">+#if OSMO_IS_BIG_ENDIAN</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t pdu_type:4,</span><br><span style="color: hsl(120, 100%, 40%);">+           frame_nr:4;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t frame_good:2,</span><br><span style="color: hsl(120, 100%, 40%);">+         rfci:6;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t header_crc:6,</span><br><span style="color: hsl(120, 100%, 40%);">+         payload_crc_hi:2;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint8_t payload_crc_lo;</span><br><span style="color: hsl(120, 100%, 40%);">+#elif OSMO_IS_LITTLE_ENDIAN</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t frame_nr:4,</span><br><span style="color: hsl(120, 100%, 40%);">+           pdu_type:4;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t rfci:6,</span><br><span style="color: hsl(120, 100%, 40%);">+               frame_good:2;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t payload_crc_hi:2,</span><br><span style="color: hsl(120, 100%, 40%);">+             header_crc:6;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t payload_crc_lo;</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t payload[0];</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_iuup_classify(bool log_errors,</span><br><span style="color: hsl(120, 100%, 40%);">+                   const char *log_label,</span><br><span style="color: hsl(120, 100%, 40%);">+                struct msgb *pdu,</span><br><span style="color: hsl(120, 100%, 40%);">+                     struct osmo_iuup_hdr_ctrl **is_ctrl,</span><br><span style="color: hsl(120, 100%, 40%);">+                  struct osmo_iuup_hdr_data **is_data);</span><br><span style="color: hsl(120, 100%, 40%);">+bool osmo_iuup_is_init(struct msgb *pdu);</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_iuup_make_init_ack(struct msgb *ack);</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_iuup_set_checksums(uint8_t *iuup_header_and_payload, unsigned int header_and_payload_len);</span><br><span>diff --git a/include/osmocom/mgcp/mgcp_codec.h b/include/osmocom/mgcp/mgcp_codec.h</span><br><span>index 3ead60a..caeecb0 100644</span><br><span>--- a/include/osmocom/mgcp/mgcp_codec.h</span><br><span>+++ b/include/osmocom/mgcp/mgcp_codec.h</span><br><span>@@ -5,3 +5,5 @@</span><br><span> int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, const struct mgcp_codec_param *param);</span><br><span> int mgcp_codec_decide(struct mgcp_conn_rtp *conn);</span><br><span> int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst, int payload_type);</span><br><span style="color: hsl(120, 100%, 40%);">+const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                             const char *subtype_name, unsigned int match_nr);</span><br><span>diff --git a/include/osmocom/mgcp/mgcp_endp.h b/include/osmocom/mgcp/mgcp_endp.h</span><br><span>index 75f093d..9c0dc8c 100644</span><br><span>--- a/include/osmocom/mgcp/mgcp_endp.h</span><br><span>+++ b/include/osmocom/mgcp/mgcp_endp.h</span><br><span>@@ -23,15 +23,27 @@</span><br><span> </span><br><span> #pragma once</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/msgb.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct sockaddr_in;</span><br><span> struct mgcp_conn;</span><br><span style="color: hsl(120, 100%, 40%);">+struct mgcp_conn_rtp;</span><br><span> struct mgcp_endpoint;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/* Callback type for RTP dispatcher functions</span><br><span style="color: hsl(0, 100%, 40%);">-   (e.g mgcp_dispatch_rtp_bridge_cb, see below) */</span><br><span style="color: hsl(0, 100%, 40%);">-typedef int (*mgcp_dispatch_rtp_cb) (int proto, struct sockaddr_in *addr,</span><br><span style="color: hsl(0, 100%, 40%);">-                                 char *buf, unsigned int buf_size,</span><br><span style="color: hsl(0, 100%, 40%);">-                               struct mgcp_conn *conn);</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_rtp_msg_ctx {</span><br><span style="color: hsl(120, 100%, 40%);">+      int proto;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct mgcp_conn_rtp *conn_src;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct sockaddr_in *from_addr;</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%);">+#define OSMO_RTP_MSG_CTX(MSGB) (*(struct osmo_rtp_msg_ctx**)&((MSGB)->dst))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define LOG_ENDP(endp, level, fmt, args...) \</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGP(DRTP, level, "%x@ " fmt, ENDPOINT_NUMBER(endp), ## args)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Callback type for RTP dispatcher functions (e.g mgcp_dispatch_rtp_bridge_cb, see below).</span><br><span style="color: hsl(120, 100%, 40%);">+ * The OSMO_RTP_MSG_CTX() should be set appropriately on the msg. */</span><br><span style="color: hsl(120, 100%, 40%);">+typedef int (*mgcp_dispatch_rtp_cb) (struct msgb *msg);</span><br><span> </span><br><span> /* Callback type for endpoint specific cleanup actions. This function</span><br><span>  * is automatically executed when a connection is freed (see mgcp_conn_free()</span><br><span>diff --git a/include/osmocom/mgcp/mgcp_internal.h b/include/osmocom/mgcp/mgcp_internal.h</span><br><span>index e9d5d2d..3e83bdf 100644</span><br><span>--- a/include/osmocom/mgcp/mgcp_internal.h</span><br><span>+++ b/include/osmocom/mgcp/mgcp_internal.h</span><br><span>@@ -37,6 +37,13 @@</span><br><span> #define CONN_ID_BTS "0"</span><br><span> #define CONN_ID_NET "1"</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#define LOG_CONN(conn, level, fmt, args...) \</span><br><span style="color: hsl(120, 100%, 40%);">+    LOGP(DRTP, level, "(%d@ I:%s) " fmt, \</span><br><span style="color: hsl(120, 100%, 40%);">+           ENDPOINT_NUMBER((conn)->endp), (conn)->id, ## args)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define LOG_CONN_RTP(conn_rtp, level, fmt, args...) \</span><br><span style="color: hsl(120, 100%, 40%);">+       LOG_CONN(conn_rtp->conn, level, fmt, ## args)</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>@@ -204,6 +211,8 @@</span><br><span>         } osmux;</span><br><span> </span><br><span>         struct rate_ctr_group *rate_ctr_group;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_iuup_cn *iuup;</span><br><span> };</span><br><span> </span><br><span> /*! Connection type, specifies which member of the union "u" in mgcp_conn</span><br><span>@@ -266,11 +275,10 @@</span><br><span> };</span><br><span> </span><br><span> int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,</span><br><span style="color: hsl(0, 100%, 40%);">-              char *buf, int rc, struct mgcp_conn_rtp *conn_src,</span><br><span style="color: hsl(120, 100%, 40%);">+            struct msgb *msg, struct mgcp_conn_rtp *conn_src,</span><br><span>            struct mgcp_conn_rtp *conn_dst);</span><br><span> int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn);</span><br><span style="color: hsl(0, 100%, 40%);">-int mgcp_dispatch_rtp_bridge_cb(int proto, struct sockaddr_in *addr, char *buf,</span><br><span style="color: hsl(0, 100%, 40%);">-                           unsigned int buf_size, struct mgcp_conn *conn);</span><br><span style="color: hsl(120, 100%, 40%);">+int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg);</span><br><span> void mgcp_cleanup_rtp_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn);</span><br><span> int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,</span><br><span>                     struct mgcp_conn_rtp *conn);</span><br><span>@@ -350,3 +358,8 @@</span><br><span> LOGPENDP((conn)->endp, cat, level, "CI:%s " fmt, \</span><br><span>          (conn)->id, \</span><br><span>          ## args)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void mgcp_patch_and_count(struct mgcp_endpoint *endp,</span><br><span style="color: hsl(120, 100%, 40%);">+                     struct mgcp_rtp_state *state,</span><br><span style="color: hsl(120, 100%, 40%);">+                         struct mgcp_rtp_end *rtp_end,</span><br><span style="color: hsl(120, 100%, 40%);">+                         struct sockaddr_in *addr, struct msgb *msg);</span><br><span>diff --git a/src/libosmo-mgcp/Makefile.am b/src/libosmo-mgcp/Makefile.am</span><br><span>index 587bdd4..7314b22 100644</span><br><span>--- a/src/libosmo-mgcp/Makefile.am</span><br><span>+++ b/src/libosmo-mgcp/Makefile.am</span><br><span>@@ -40,4 +40,6 @@</span><br><span>      mgcp_conn.c \</span><br><span>        mgcp_stat.c \</span><br><span>        mgcp_endp.c \</span><br><span style="color: hsl(120, 100%, 40%);">+ iuup_protocol.c \</span><br><span style="color: hsl(120, 100%, 40%);">+     iuup_cn_node.c \</span><br><span>     $(NULL)</span><br><span>diff --git a/src/libosmo-mgcp/iuup_cn_node.c b/src/libosmo-mgcp/iuup_cn_node.c</span><br><span>new file mode 100644</span><br><span>index 0000000..239a159</span><br><span>--- /dev/null</span><br><span>+++ b/src/libosmo-mgcp/iuup_cn_node.c</span><br><span>@@ -0,0 +1,211 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */</span><br><span style="color: hsl(120, 100%, 40%);">+/* IuUP Core Network side protocol handling, minimal implementation */</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) 2018 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: Neels Hofmeyr <neels@hofmeyr.de></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 <talloc.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <string.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <arpa/inet.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/msgb.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/netif/rtp.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mgcp/iuup_cn_node.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mgcp/iuup_protocol.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mgcp/debug.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define LOG_IUUP_CN(cn, level, fmt, args...) \</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGP(DIUUP, level, "(%s) " fmt, (cn)->name, ## args)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_iuup_cn *osmo_iuup_cn_init(void *ctx, struct osmo_iuup_cn_cfg *cfg,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 const char *name_fmt, ...)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  va_list ap;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_iuup_cn *cn = talloc_zero(ctx, struct osmo_iuup_cn);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(cn);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    cn->cfg = *cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!name_fmt)</span><br><span style="color: hsl(120, 100%, 40%);">+                name_fmt = "-";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   va_start(ap, name_fmt);</span><br><span style="color: hsl(120, 100%, 40%);">+       cn->name = talloc_vasprintf(cn, name_fmt, ap);</span><br><span style="color: hsl(120, 100%, 40%);">+     va_end(ap);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DIUUP, LOGL_INFO, "(%s) Initializing IuUP node\n", cn->name);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!osmo_identifier_valid(cn->name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGP(DIUUP, LOGL_ERROR, "Attempting to set illegal id for IuUP CN instance: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_quote_str(cn->name, -1));</span><br><span style="color: hsl(120, 100%, 40%);">+                talloc_free(cn);</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return cn;</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%);">+void osmo_iuup_cn_free(struct osmo_iuup_cn *cn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   talloc_free(cn);</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%);">+static int rx_data(struct osmo_iuup_cn *cn, struct msgb *pdu,</span><br><span style="color: hsl(120, 100%, 40%);">+             struct osmo_iuup_hdr_data *hdr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Remove the IuUP bit from the middle of the buffer by writing the RTP header forward. */</span><br><span style="color: hsl(120, 100%, 40%);">+    /* And append AMR 12.2k header "0xf03c". - AD HOC fix */</span><br><span style="color: hsl(120, 100%, 40%);">+    unsigned int pre_hdr_len = ((uint8_t*)hdr) - pdu->data;</span><br><span style="color: hsl(120, 100%, 40%);">+    memmove(pdu->data + sizeof(*hdr) - 2, pdu->data, pre_hdr_len);</span><br><span style="color: hsl(120, 100%, 40%);">+  ((uint8_t*)hdr)[2] = 0xf0;</span><br><span style="color: hsl(120, 100%, 40%);">+    ((uint8_t*)hdr)[3] = 0x3c;</span><br><span style="color: hsl(120, 100%, 40%);">+    msgb_pull(pdu, sizeof(*hdr) - 2);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGP(DIUUP, LOGL_DEBUG, "(%s) IuUP stripping IuUP header from RTP data\n", cn->name);</span><br><span style="color: hsl(120, 100%, 40%);">+    cn->cfg.rx_payload(pdu, cn->cfg.node_priv);</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%);">+static int tx_init_ack(struct osmo_iuup_cn *cn, struct msgb *src_pdu)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Send Initialization Ack PDU back to the sender */</span><br><span style="color: hsl(120, 100%, 40%);">+  int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct msgb *ack = msgb_alloc(4096, "IuUP Initialization Ack");</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(ack);</span><br><span style="color: hsl(120, 100%, 40%);">+     ack->dst = src_pdu->dst;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Just copy the RTP header that was sent... TODO: tweak some RTP values?? */</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(msgb_put(ack, sizeof(struct rtp_hdr)), src_pdu->data, sizeof(struct rtp_hdr));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_iuup_make_init_ack(ack);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       LOGP(DIUUP, LOGL_DEBUG, "(%s) Sending Initialization ACK %p\n", cn->name, cn->cfg.node_priv);</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = cn->cfg.tx_msg(ack, cn->cfg.node_priv);</span><br><span style="color: hsl(120, 100%, 40%);">+    msgb_free(ack);</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%);">+static int rx_control(struct osmo_iuup_cn *cn, struct msgb *pdu,</span><br><span style="color: hsl(120, 100%, 40%);">+                   struct osmo_iuup_hdr_ctrl *hdr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      switch (hdr->procedure) {</span><br><span style="color: hsl(120, 100%, 40%);">+  case OSMO_IUUP_PROC_INITIALIZATION:</span><br><span style="color: hsl(120, 100%, 40%);">+           switch (hdr->ack_nack) {</span><br><span style="color: hsl(120, 100%, 40%);">+           case OSMO_IUUP_ACKNACK_PROCEDURE:</span><br><span style="color: hsl(120, 100%, 40%);">+                     LOGP(DIUUP, LOGL_INFO, "(%s) Rx IuUP Initialization, sending ACK\n", cn->name);</span><br><span style="color: hsl(120, 100%, 40%);">+                  cn->rtp_payload_type = ((struct rtp_hdr*)pdu->data)->payload_type;</span><br><span style="color: hsl(120, 100%, 40%);">+                   return tx_init_ack(cn, pdu);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                default:</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGP(DIUUP, LOGL_DEBUG, "(%s) Rx IuUP Initialization, unhandled ack_nack = %d\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                        cn->name, hdr->ack_nack);</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%);">+             /* Continue to log "unexpected procedure" below. */</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%);">+      case OSMO_IUUP_PROC_ERROR_EVENT:</span><br><span style="color: hsl(120, 100%, 40%);">+              {</span><br><span style="color: hsl(120, 100%, 40%);">+                     union osmo_iuup_hdr_ctrl_payload *p = (void*)hdr->payload;</span><br><span style="color: hsl(120, 100%, 40%);">+                 LOGP(DIUUP, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                            "(%s) Rx IuUP Error Event: distance=%u, cause=%u=\"%s\"\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                       cn->name, p->error_event.error_distance, p->error_event.error_cause,</span><br><span style="color: hsl(120, 100%, 40%);">+                         osmo_iuup_error_cause_name(p->error_event.error_cause));</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%);">+   default:</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%);">+     LOG_IUUP_CN(cn, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+               "Rx control PDU with unexpected procedure: 0x%x acknack=0x%x\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                    hdr->procedure, hdr->ack_nack);</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%);">+/* Feed a received PDU to the IuUP CN node. This function takes ownership of the msgb, it must not be</span><br><span style="color: hsl(120, 100%, 40%);">+ * freed by the caller. */</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_iuup_cn_rx_pdu(struct osmo_iuup_cn *cn, struct msgb *pdu)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_iuup_hdr_ctrl *is_ctrl;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_iuup_hdr_data *is_data;</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%);">+     rc = osmo_iuup_classify(true, cn->name, pdu, &is_ctrl, &is_data);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (rc)</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%);">+  if (is_ctrl)</span><br><span style="color: hsl(120, 100%, 40%);">+          return rx_control(cn, pdu, is_ctrl);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (is_data)</span><br><span style="color: hsl(120, 100%, 40%);">+          return rx_data(cn, pdu, is_data);</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%);">+static uint8_t next_frame_nr(struct osmo_iuup_cn *cn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     uint8_t frame_nr = cn->next_frame_nr;</span><br><span style="color: hsl(120, 100%, 40%);">+      cn->next_frame_nr = (frame_nr + 1) & 0x0f;</span><br><span style="color: hsl(120, 100%, 40%);">+     return frame_nr;</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%);">+/* Send this RTP packet to the IuUP peer: add IuUP header and call the tx_msg() to transmit the resulting</span><br><span style="color: hsl(120, 100%, 40%);">+ * message to the IuUP peer.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Returns 0 on success, negative on error. */</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_iuup_cn_tx_payload(struct osmo_iuup_cn *cn, struct msgb *pdu)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct rtp_hdr *rtp_was, *rtp;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_iuup_hdr_data *iuup_hdr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Splice an IuUP header in between RTP header and payload data */</span><br><span style="color: hsl(120, 100%, 40%);">+    rtp_was = (void*)pdu->data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* copy the RTP header part backwards by the size needed for the IuUP header */</span><br><span style="color: hsl(120, 100%, 40%);">+       /* also strips 2 bytes from the front of RTP payload - AMR header - AD HOC fix */</span><br><span style="color: hsl(120, 100%, 40%);">+     rtp = (void*)msgb_push(pdu, sizeof(*iuup_hdr) - 2);</span><br><span style="color: hsl(120, 100%, 40%);">+   memmove(rtp, rtp_was, sizeof(*rtp));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* The IuUP side negotiated a payload type number to use during Initialization. The RTP packet going to the IuUP</span><br><span style="color: hsl(120, 100%, 40%);">+       * peer should reflect this payload_type. This should already have happened in mgcp_patch_pt(), but can't hurt</span><br><span style="color: hsl(120, 100%, 40%);">+     * to patch over it again. */</span><br><span style="color: hsl(120, 100%, 40%);">+ rtp->payload_type = cn->rtp_payload_type;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     iuup_hdr = (void*)rtp->data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     *iuup_hdr = (struct osmo_iuup_hdr_data){</span><br><span style="color: hsl(120, 100%, 40%);">+              .pdu_type = OSMO_IUUP_PDU_DATA_WITH_CRC,</span><br><span style="color: hsl(120, 100%, 40%);">+              .frame_nr = next_frame_nr(cn),</span><br><span style="color: hsl(120, 100%, 40%);">+                .frame_good = OSMO_IUUP_FRAME_GOOD,</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%);">+  osmo_iuup_set_checksums((uint8_t*)iuup_hdr, pdu->tail - (uint8_t*)iuup_hdr);</span><br><span style="color: hsl(120, 100%, 40%);">+       LOGP(DIUUP, LOGL_DEBUG, "(%s) IuUP inserting IuUP header in RTP data (frame nr %u)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+           cn->name, iuup_hdr->frame_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return cn->cfg.tx_msg(pdu, cn->cfg.node_priv);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/libosmo-mgcp/iuup_protocol.c b/src/libosmo-mgcp/iuup_protocol.c</span><br><span>new file mode 100644</span><br><span>index 0000000..bfb009d</span><br><span>--- /dev/null</span><br><span>+++ b/src/libosmo-mgcp/iuup_protocol.c</span><br><span>@@ -0,0 +1,286 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */</span><br><span style="color: hsl(120, 100%, 40%);">+/* IuUP Core Network side protocol, minimal implementation */</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) 2018 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: Neels Hofmeyr <neels@hofmeyr.de></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 <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mgcp/iuup_protocol.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/netif/rtp.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Calculating two bytes of CRC is ok to do by a loop */</span><br><span style="color: hsl(120, 100%, 40%);">+static uint8_t header_crc6(const uint8_t *hdr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    int bit;</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Polynomial: D^6 + D^5 + D^3 + D^2 + D^1 + 1</span><br><span style="color: hsl(120, 100%, 40%);">+     * that's 1101111 or 0x6f;</span><br><span style="color: hsl(120, 100%, 40%);">+     * align its lowest bit with a uint16_t's highest bit: */</span><br><span style="color: hsl(120, 100%, 40%);">+    uint32_t polynomial = 0x6f << 15; // 00110111 10000000 00000000</span><br><span style="color: hsl(120, 100%, 40%);">+    uint32_t remainder = ( ((uint32_t)hdr[0]) << 8 | hdr[1] ) << 6;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    for (bit = 15; bit >= 0; bit--)</span><br><span style="color: hsl(120, 100%, 40%);">+    {</span><br><span style="color: hsl(120, 100%, 40%);">+        if (remainder & (0x40 << bit))</span><br><span style="color: hsl(120, 100%, 40%);">+            remainder ^= polynomial;</span><br><span style="color: hsl(120, 100%, 40%);">+        polynomial >>= 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%);">+    return remainder;</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%);">+ * Charles Michael Heard's CRC-10 code, from</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ *      http://web.archive.org/web/20061005231950/http://cell-relay.indiana.edu/cell-relay/publications/software/CRC/crc10.html</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * with the CRC table initialized with values computed by</span><br><span style="color: hsl(120, 100%, 40%);">+ * his "gen_byte_crc10_table()" routine, rather than by calling that</span><br><span style="color: hsl(120, 100%, 40%);">+ * routine at run time, and with various data type cleanups.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static const uint16_t byte_crc10_table[256] = {</span><br><span style="color: hsl(120, 100%, 40%);">+      0x0000, 0x0233, 0x0255, 0x0066, 0x0299, 0x00aa, 0x00cc, 0x02ff,</span><br><span style="color: hsl(120, 100%, 40%);">+       0x0301, 0x0132, 0x0154, 0x0367, 0x0198, 0x03ab, 0x03cd, 0x01fe,</span><br><span style="color: hsl(120, 100%, 40%);">+       0x0031, 0x0202, 0x0264, 0x0057, 0x02a8, 0x009b, 0x00fd, 0x02ce,</span><br><span style="color: hsl(120, 100%, 40%);">+       0x0330, 0x0103, 0x0165, 0x0356, 0x01a9, 0x039a, 0x03fc, 0x01cf,</span><br><span style="color: hsl(120, 100%, 40%);">+       0x0062, 0x0251, 0x0237, 0x0004, 0x02fb, 0x00c8, 0x00ae, 0x029d,</span><br><span style="color: hsl(120, 100%, 40%);">+       0x0363, 0x0150, 0x0136, 0x0305, 0x01fa, 0x03c9, 0x03af, 0x019c,</span><br><span style="color: hsl(120, 100%, 40%);">+       0x0053, 0x0260, 0x0206, 0x0035, 0x02ca, 0x00f9, 0x009f, 0x02ac,</span><br><span style="color: hsl(120, 100%, 40%);">+       0x0352, 0x0161, 0x0107, 0x0334, 0x01cb, 0x03f8, 0x039e, 0x01ad,</span><br><span style="color: hsl(120, 100%, 40%);">+       0x00c4, 0x02f7, 0x0291, 0x00a2, 0x025d, 0x006e, 0x0008, 0x023b,</span><br><span style="color: hsl(120, 100%, 40%);">+       0x03c5, 0x01f6, 0x0190, 0x03a3, 0x015c, 0x036f, 0x0309, 0x013a,</span><br><span style="color: hsl(120, 100%, 40%);">+       0x00f5, 0x02c6, 0x02a0, 0x0093, 0x026c, 0x005f, 0x0039, 0x020a,</span><br><span style="color: hsl(120, 100%, 40%);">+       0x03f4, 0x01c7, 0x01a1, 0x0392, 0x016d, 0x035e, 0x0338, 0x010b,</span><br><span style="color: hsl(120, 100%, 40%);">+       0x00a6, 0x0295, 0x02f3, 0x00c0, 0x023f, 0x000c, 0x006a, 0x0259,</span><br><span style="color: hsl(120, 100%, 40%);">+       0x03a7, 0x0194, 0x01f2, 0x03c1, 0x013e, 0x030d, 0x036b, 0x0158,</span><br><span style="color: hsl(120, 100%, 40%);">+       0x0097, 0x02a4, 0x02c2, 0x00f1, 0x020e, 0x003d, 0x005b, 0x0268,</span><br><span style="color: hsl(120, 100%, 40%);">+       0x0396, 0x01a5, 0x01c3, 0x03f0, 0x010f, 0x033c, 0x035a, 0x0169,</span><br><span style="color: hsl(120, 100%, 40%);">+       0x0188, 0x03bb, 0x03dd, 0x01ee, 0x0311, 0x0122, 0x0144, 0x0377,</span><br><span style="color: hsl(120, 100%, 40%);">+       0x0289, 0x00ba, 0x00dc, 0x02ef, 0x0010, 0x0223, 0x0245, 0x0076,</span><br><span style="color: hsl(120, 100%, 40%);">+       0x01b9, 0x038a, 0x03ec, 0x01df, 0x0320, 0x0113, 0x0175, 0x0346,</span><br><span style="color: hsl(120, 100%, 40%);">+       0x02b8, 0x008b, 0x00ed, 0x02de, 0x0021, 0x0212, 0x0274, 0x0047,</span><br><span style="color: hsl(120, 100%, 40%);">+       0x01ea, 0x03d9, 0x03bf, 0x018c, 0x0373, 0x0140, 0x0126, 0x0315,</span><br><span style="color: hsl(120, 100%, 40%);">+       0x02eb, 0x00d8, 0x00be, 0x028d, 0x0072, 0x0241, 0x0227, 0x0014,</span><br><span style="color: hsl(120, 100%, 40%);">+       0x01db, 0x03e8, 0x038e, 0x01bd, 0x0342, 0x0171, 0x0117, 0x0324,</span><br><span style="color: hsl(120, 100%, 40%);">+       0x02da, 0x00e9, 0x008f, 0x02bc, 0x0043, 0x0270, 0x0216, 0x0025,</span><br><span style="color: hsl(120, 100%, 40%);">+       0x014c, 0x037f, 0x0319, 0x012a, 0x03d5, 0x01e6, 0x0180, 0x03b3,</span><br><span style="color: hsl(120, 100%, 40%);">+       0x024d, 0x007e, 0x0018, 0x022b, 0x00d4, 0x02e7, 0x0281, 0x00b2,</span><br><span style="color: hsl(120, 100%, 40%);">+       0x017d, 0x034e, 0x0328, 0x011b, 0x03e4, 0x01d7, 0x01b1, 0x0382,</span><br><span style="color: hsl(120, 100%, 40%);">+       0x027c, 0x004f, 0x0029, 0x021a, 0x00e5, 0x02d6, 0x02b0, 0x0083,</span><br><span style="color: hsl(120, 100%, 40%);">+       0x012e, 0x031d, 0x037b, 0x0148, 0x03b7, 0x0184, 0x01e2, 0x03d1,</span><br><span style="color: hsl(120, 100%, 40%);">+       0x022f, 0x001c, 0x007a, 0x0249, 0x00b6, 0x0285, 0x02e3, 0x00d0,</span><br><span style="color: hsl(120, 100%, 40%);">+       0x011f, 0x032c, 0x034a, 0x0179, 0x0386, 0x01b5, 0x01d3, 0x03e0,</span><br><span style="color: hsl(120, 100%, 40%);">+       0x021e, 0x002d, 0x004b, 0x0278, 0x0087, 0x02b4, 0x02d2, 0x00e1</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%);">+static uint16_t crc10(uint16_t crc10_accum, const uint8_t *payload, unsigned int payload_len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      for (i = 0; i < payload_len; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                crc10_accum = ((crc10_accum << 8) & 0x300)</span><br><span style="color: hsl(120, 100%, 40%);">+                  ^ byte_crc10_table[(crc10_accum >> 2) & 0xff]</span><br><span style="color: hsl(120, 100%, 40%);">+                       ^ payload[i];</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     return crc10_accum;</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%);">+/* When a payload of a multiple of bytes has run through, we need to still feed 10 bits of zeros into the</span><br><span style="color: hsl(120, 100%, 40%);">+ * CRC10 to get the payload's checksum result that we can send to a peer. That can't be done with above</span><br><span style="color: hsl(120, 100%, 40%);">+ * table, because it acts as if full 16 bits are fed. This stops after 10 bits. */</span><br><span style="color: hsl(120, 100%, 40%);">+static uint16_t crc10_remainder(uint16_t crc10_accum)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    int bit;</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Polynomial: D^10 + D^9 + D^5 + D^4 + D^1 + 1</span><br><span style="color: hsl(120, 100%, 40%);">+     * that's 11000110011 or 0x633;</span><br><span style="color: hsl(120, 100%, 40%);">+     * align its lowest bit with a 10bit value's highest bit: */</span><br><span style="color: hsl(120, 100%, 40%);">+    uint32_t polynomial = 0x633 << 9; // 1100 01100110 00000000</span><br><span style="color: hsl(120, 100%, 40%);">+    uint32_t remainder = ((uint32_t)crc10_accum) << 10;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Run on 10 bits */</span><br><span style="color: hsl(120, 100%, 40%);">+    for (bit = 9; bit >= 0; bit--)</span><br><span style="color: hsl(120, 100%, 40%);">+    {</span><br><span style="color: hsl(120, 100%, 40%);">+        if (remainder & ((1 << 10) << bit))</span><br><span style="color: hsl(120, 100%, 40%);">+            remainder ^= polynomial;</span><br><span style="color: hsl(120, 100%, 40%);">+        polynomial >>= 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%);">+    return remainder & 0x3ff;</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%);">+static uint16_t payload_crc10(const uint8_t *payload, unsigned int payload_len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t crc10_accum = crc10(0, payload, payload_len);</span><br><span style="color: hsl(120, 100%, 40%);">+        return crc10_remainder(crc10_accum);</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%);">+/* Given an IuUP PDU data block, write the correct header and payload CRC checksums at the right places.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_iuup_set_checksums(uint8_t *iuup_header_and_payload, unsigned int header_and_payload_len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      /* For both data and ctrl, the checksums and payload are at the same offset */</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_iuup_hdr_data *hdr = (void*)iuup_header_and_payload;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint16_t crc;</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int payload_len;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   hdr->header_crc = header_crc6(iuup_header_and_payload);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  payload_len = iuup_header_and_payload + header_and_payload_len - hdr->payload;</span><br><span style="color: hsl(120, 100%, 40%);">+     crc = payload_crc10(hdr->payload, payload_len);</span><br><span style="color: hsl(120, 100%, 40%);">+    hdr->payload_crc_hi = (crc >> 8) & 0x3;</span><br><span style="color: hsl(120, 100%, 40%);">+  hdr->payload_crc_lo = crc & 0xff;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Validate minimum message sizes, IuUP PDU type, header- and payload checksums. If it is a Control</span><br><span style="color: hsl(120, 100%, 40%);">+ * Procedure PDU, return the header position in is_ctrl, if it is a Data PDU, return the header position</span><br><span style="color: hsl(120, 100%, 40%);">+ * in is_data. If log_errors is true, log on DIUUP with the given log label for context. Return NULL in</span><br><span style="color: hsl(120, 100%, 40%);">+ * both is_ctrl and is_data, and return a negative error code if the PDU could not be identified as a</span><br><span style="color: hsl(120, 100%, 40%);">+ * valid RTP PDU containing an IuUP part. */</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_iuup_classify(bool log_errors,</span><br><span style="color: hsl(120, 100%, 40%);">+                const char *log_label,</span><br><span style="color: hsl(120, 100%, 40%);">+                struct msgb *pdu,</span><br><span style="color: hsl(120, 100%, 40%);">+                     struct osmo_iuup_hdr_ctrl **is_ctrl,</span><br><span style="color: hsl(120, 100%, 40%);">+                  struct osmo_iuup_hdr_data **is_data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct rtp_hdr *rtp = (void*)pdu->data;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_iuup_hdr_ctrl *hdr = (void*)rtp->data;</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int payload_len;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint16_t crc_calculated;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint16_t crc_from_peer;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define ERR(fmt, args...) do { \</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (log_errors) \</span><br><span style="color: hsl(120, 100%, 40%);">+                             LOGP(DIUUP, LOGL_ERROR, "(%s) " fmt, log_label? : "-", ## args); \</span><br><span style="color: hsl(120, 100%, 40%);">+                        return -EINVAL; \</span><br><span style="color: hsl(120, 100%, 40%);">+             } while (0)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (is_ctrl)</span><br><span style="color: hsl(120, 100%, 40%);">+          *is_ctrl = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+      if (is_data)</span><br><span style="color: hsl(120, 100%, 40%);">+          *is_data = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* We need at least a header of 4 bytes. The osmo_iuup_hdr_ctrl already includes a byte of</span><br><span style="color: hsl(120, 100%, 40%);">+     * payload, so use osmo_iuup_hdr_data to check the minimum here. */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (pdu->len < (sizeof(*rtp) + sizeof(struct osmo_iuup_hdr_data)))</span><br><span style="color: hsl(120, 100%, 40%);">+              ERR("IuUP PDU too short: %u\n", pdu->len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Let's not validate checksums if the header type isn't sane */</span><br><span style="color: hsl(120, 100%, 40%);">+      switch (hdr->pdu_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+   case OSMO_IUUP_PDU_DATA_WITH_CRC:</span><br><span style="color: hsl(120, 100%, 40%);">+             /* If the caller isn't interested in data PDUs, cut short here. */</span><br><span style="color: hsl(120, 100%, 40%);">+                if (!is_data)</span><br><span style="color: hsl(120, 100%, 40%);">+                 return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case OSMO_IUUP_PDU_CONTROL_PROCEDURE:</span><br><span style="color: hsl(120, 100%, 40%);">+         /* If the caller isn't interested in control PDUs, cut short here. */</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!is_ctrl)</span><br><span style="color: hsl(120, 100%, 40%);">+                 return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+             if (pdu->len < (sizeof(*rtp) + sizeof(struct osmo_iuup_hdr_ctrl)))</span><br><span style="color: hsl(120, 100%, 40%);">+                      ERR("IuUP control PDU too short: %u\n", pdu->len);</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%);">+              ERR("IuUP with invalid type: %u\n", hdr->pdu_type);</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%);">+   /* For both data and ctrl, the checksums and payload are at the same offset */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      crc_calculated = header_crc6((uint8_t*)hdr);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (crc_calculated != hdr->header_crc)</span><br><span style="color: hsl(120, 100%, 40%);">+             ERR("IuUP PDU with invalid header CRC (peer sent 0x%x, calculated 0x%x)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+             hdr->header_crc, crc_calculated);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    payload_len = pdu->tail - hdr->payload;</span><br><span style="color: hsl(120, 100%, 40%);">+ crc_calculated = payload_crc10(hdr->payload, payload_len);</span><br><span style="color: hsl(120, 100%, 40%);">+ crc_from_peer = (((uint16_t)hdr->payload_crc_hi) << 8) | hdr->payload_crc_lo;</span><br><span style="color: hsl(120, 100%, 40%);">+     if (crc_from_peer != crc_calculated)</span><br><span style="color: hsl(120, 100%, 40%);">+          ERR("IuUP PDU with invalid payload CRC (peer sent 0x%x, calculated 0x%x)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                    crc_from_peer, crc_calculated);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (hdr->pdu_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+   case OSMO_IUUP_PDU_DATA_WITH_CRC:</span><br><span style="color: hsl(120, 100%, 40%);">+             if (is_data)</span><br><span style="color: hsl(120, 100%, 40%);">+                  *is_data = (void*)hdr;</span><br><span style="color: hsl(120, 100%, 40%);">+                return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     case OSMO_IUUP_PDU_CONTROL_PROCEDURE:</span><br><span style="color: hsl(120, 100%, 40%);">+         if (is_ctrl)</span><br><span style="color: hsl(120, 100%, 40%);">+                  *is_ctrl = hdr;</span><br><span style="color: hsl(120, 100%, 40%);">+               return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     default:</span><br><span style="color: hsl(120, 100%, 40%);">+              ERR("IuUP with invalid type: %u\n", hdr->pdu_type);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+#undef ERR</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 true if this RTP packet contains an IuUP Initialization header (detect IuUP peer). */</span><br><span style="color: hsl(120, 100%, 40%);">+bool osmo_iuup_is_init(struct msgb *pdu)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_iuup_hdr_ctrl *is_ctrl;</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_iuup_classify(false, NULL, pdu, &is_ctrl, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+     return is_ctrl</span><br><span style="color: hsl(120, 100%, 40%);">+                && is_ctrl->procedure == OSMO_IUUP_PROC_INITIALIZATION</span><br><span style="color: hsl(120, 100%, 40%);">+             && is_ctrl->ack_nack == OSMO_IUUP_ACKNACK_PROCEDURE;</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%);">+/* Append an IuUP Initialization ACK message */</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_iuup_make_init_ack(struct msgb *ack)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Send Initialization Ack PDU back to the sender */</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_iuup_hdr_ctrl *hdr;</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(ack);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   hdr = (void*)msgb_put(ack, sizeof(*hdr));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   *hdr = (struct osmo_iuup_hdr_ctrl){</span><br><span style="color: hsl(120, 100%, 40%);">+           .pdu_type = OSMO_IUUP_PDU_CONTROL_PROCEDURE,</span><br><span style="color: hsl(120, 100%, 40%);">+          .ack_nack = OSMO_IUUP_ACKNACK_ACK,</span><br><span style="color: hsl(120, 100%, 40%);">+            .procedure = OSMO_IUUP_PROC_INITIALIZATION,</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%);">+  osmo_iuup_set_checksums((uint8_t*)hdr, sizeof(*hdr));</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 struct value_string osmo_iuup_error_cause_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+       { 0, "CRC error of frame header" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { 1, "CRC error of frame payload" },</span><br><span style="color: hsl(120, 100%, 40%);">+        { 2, "Unexpected frame number" },</span><br><span style="color: hsl(120, 100%, 40%);">+   { 3, "Frame loss" },</span><br><span style="color: hsl(120, 100%, 40%);">+        { 4, "PDU type unknown" },</span><br><span style="color: hsl(120, 100%, 40%);">+  { 5, "Unknown procedure" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { 6, "Unknown reserved value" },</span><br><span style="color: hsl(120, 100%, 40%);">+    { 7, "Unknown field" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { 8, "Frame too short" },</span><br><span style="color: hsl(120, 100%, 40%);">+   { 9, "Missing fields" },</span><br><span style="color: hsl(120, 100%, 40%);">+    { 16, "Unexpected PDU type" },</span><br><span style="color: hsl(120, 100%, 40%);">+      { 17, "spare" },</span><br><span style="color: hsl(120, 100%, 40%);">+    { 18, "Unexpected procedure" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { 19, "Unexpected RFCI" },</span><br><span style="color: hsl(120, 100%, 40%);">+  { 20, "Unexpected value" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { 42, "Initialisation failure" },</span><br><span style="color: hsl(120, 100%, 40%);">+   { 43, "Initialisation failure (network error, timer expiry)" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { 44, "Initialisation failure (Iu UP function error, repeated NACK)" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { 45, "Rate control failure" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { 46, "Error event failure" },</span><br><span style="color: hsl(120, 100%, 40%);">+      { 47, "Time Alignment not supported" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { 48, "Requested Time Alignment not possible" },</span><br><span style="color: hsl(120, 100%, 40%);">+    { 49, "Iu UP Mode version not supported" },</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_codec.c b/src/libosmo-mgcp/mgcp_codec.c</span><br><span>index 93a8157..cf9f942 100644</span><br><span>--- a/src/libosmo-mgcp/mgcp_codec.c</span><br><span>+++ b/src/libosmo-mgcp/mgcp_codec.c</span><br><span>@@ -454,3 +454,19 @@</span><br><span> </span><br><span>   return codec_dst->payload_type;</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                                const char *subtype_name, unsigned int match_nr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   int i;</span><br><span style="color: hsl(120, 100%, 40%);">+        for (i = 0; i < conn->end.codecs_assigned; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+               if (!strcmp(conn->end.codecs[i].subtype_name, subtype_name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (match_nr) {</span><br><span style="color: hsl(120, 100%, 40%);">+                               match_nr--;</span><br><span style="color: hsl(120, 100%, 40%);">+                           continue;</span><br><span style="color: hsl(120, 100%, 40%);">+                     }</span><br><span style="color: hsl(120, 100%, 40%);">+                     return &conn->end.codecs[i];</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     return NULL;</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 bb29d2b..af2a647 100644</span><br><span>--- a/src/libosmo-mgcp/mgcp_network.c</span><br><span>+++ b/src/libosmo-mgcp/mgcp_network.c</span><br><span>@@ -45,6 +45,8 @@</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(120, 100%, 40%);">+#include <osmocom/mgcp/iuup_cn_node.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mgcp/iuup_protocol.h></span><br><span> </span><br><span> </span><br><span> #define RTP_SEQ_MOD               (1 << 16)</span><br><span>@@ -52,11 +54,13 @@</span><br><span> #define RTP_MAX_MISORDER       100</span><br><span> #define RTP_BUF_SIZE             4096</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-enum {</span><br><span style="color: hsl(120, 100%, 40%);">+enum rtp_proto {</span><br><span>     MGCP_PROTO_RTP,</span><br><span>      MGCP_PROTO_RTCP,</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static int rx_rtp(struct msgb *msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! Determine the local rtp bind IP-address.</span><br><span>  *  \param[out] addr caller provided memory to store the resulting IP-Address</span><br><span>  *  \param[in] endp mgcp endpoint, that holds a copy of the VTY parameters</span><br><span>@@ -469,19 +473,38 @@</span><br><span>  * Patch the payload type of an RTP packet so that it uses the payload type</span><br><span>  * that is valid for the destination connection (conn_dst) */</span><br><span> static int mgcp_patch_pt(struct mgcp_conn_rtp *conn_src,</span><br><span style="color: hsl(0, 100%, 40%);">-                    struct mgcp_conn_rtp *conn_dst, char *data, int len)</span><br><span style="color: hsl(120, 100%, 40%);">+                  struct mgcp_conn_rtp *conn_dst, struct msgb *msg)</span><br><span> {</span><br><span>      struct rtp_hdr *rtp_hdr;</span><br><span>     uint8_t pt_in;</span><br><span>       int pt_out;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(len >= sizeof(struct rtp_hdr));</span><br><span style="color: hsl(0, 100%, 40%);">-  rtp_hdr = (struct rtp_hdr *)data;</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(msg->len >= sizeof(struct rtp_hdr));</span><br><span style="color: hsl(120, 100%, 40%);">+        rtp_hdr = (struct rtp_hdr *)msg->data;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   pt_in = rtp_hdr->payload_type;</span><br><span style="color: hsl(0, 100%, 40%);">-       pt_out = mgcp_codec_pt_translate(conn_src, conn_dst, pt_in);</span><br><span style="color: hsl(0, 100%, 40%);">-    if (pt_out < 0)</span><br><span style="color: hsl(0, 100%, 40%);">-              return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       if (conn_src->iuup) {</span><br><span style="color: hsl(120, 100%, 40%);">+              /* The source is an IuUP payload. We have received a dynamic payload type number on the IuUP side, and</span><br><span style="color: hsl(120, 100%, 40%);">+                 * towards the pure RTP side it should go out as "AMR/8000". Make sure that the payload type number in</span><br><span style="color: hsl(120, 100%, 40%);">+               * the RTP packet matches the a=rtpmap:N payload type number configured for AMR. */</span><br><span style="color: hsl(120, 100%, 40%);">+           const struct mgcp_rtp_codec *amr_codec = mgcp_codec_pt_find_by_subtype_name(conn_dst, "AMR", 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          if (!amr_codec) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     /* There is no AMR codec configured on the outgoing conn. */</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%);">+           pt_out = amr_codec->payload_type;</span><br><span style="color: hsl(120, 100%, 40%);">+  } else if (conn_dst->iuup) {</span><br><span style="color: hsl(120, 100%, 40%);">+               /* The destination is an IuUP payload. Use whatever payload number was negotiated during IuUP</span><br><span style="color: hsl(120, 100%, 40%);">+          * Initialization. */</span><br><span style="color: hsl(120, 100%, 40%);">+         pt_out = conn_dst->iuup->rtp_payload_type;</span><br><span style="color: hsl(120, 100%, 40%);">+      } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              /* Both sides are normal RTP payloads. Consult the rtpmap settings received by SDP. */</span><br><span style="color: hsl(120, 100%, 40%);">+                pt_in = rtp_hdr->payload_type;</span><br><span style="color: hsl(120, 100%, 40%);">+             pt_out = mgcp_codec_pt_translate(conn_src, conn_dst, pt_in);</span><br><span style="color: hsl(120, 100%, 40%);">+          if (pt_out < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                    return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span> </span><br><span>        rtp_hdr->payload_type = (uint8_t) pt_out;</span><br><span>         return 0;</span><br><span>@@ -496,7 +519,7 @@</span><br><span> void mgcp_patch_and_count(struct mgcp_endpoint *endp,</span><br><span>                       struct mgcp_rtp_state *state,</span><br><span>                        struct mgcp_rtp_end *rtp_end,</span><br><span style="color: hsl(0, 100%, 40%);">-                   struct sockaddr_in *addr, char *data, int len)</span><br><span style="color: hsl(120, 100%, 40%);">+                        struct sockaddr_in *addr, struct msgb *msg)</span><br><span> {</span><br><span>   uint32_t arrival_time;</span><br><span>       int32_t transit;</span><br><span>@@ -504,11 +527,12 @@</span><br><span>     uint32_t timestamp, ssrc;</span><br><span>    struct rtp_hdr *rtp_hdr;</span><br><span>     int payload = rtp_end->codec->payload_type;</span><br><span style="color: hsl(120, 100%, 40%);">+     unsigned int len = msg->len;</span><br><span> </span><br><span>  if (len < sizeof(*rtp_hdr))</span><br><span>               return;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     rtp_hdr = (struct rtp_hdr *)data;</span><br><span style="color: hsl(120, 100%, 40%);">+     rtp_hdr = (struct rtp_hdr *)msg->data;</span><br><span>    seq = ntohs(rtp_hdr->sequence);</span><br><span>   timestamp = ntohl(rtp_hdr->timestamp);</span><br><span>    arrival_time = get_current_ts(rtp_end->codec->rate);</span><br><span>@@ -751,15 +775,14 @@</span><br><span> </span><br><span> /* Forward data to a debug tap. This is debug function that is intended for</span><br><span>  * debugging the voice traffic with tools like gstreamer */</span><br><span style="color: hsl(0, 100%, 40%);">-static void forward_data(int fd, struct mgcp_rtp_tap *tap, const char *buf,</span><br><span style="color: hsl(0, 100%, 40%);">-                  int len)</span><br><span style="color: hsl(120, 100%, 40%);">+static void forward_data(int fd, struct mgcp_rtp_tap *tap, struct msgb *msg)</span><br><span> {</span><br><span>         int rc;</span><br><span> </span><br><span>  if (!tap->enabled)</span><br><span>                return;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     rc = sendto(fd, buf, len, 0, (struct sockaddr *)&tap->forward,</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = sendto(fd, msg->data, msg->len, 0, (struct sockaddr *)&tap->forward,</span><br><span>                   sizeof(tap->forward));</span><br><span> </span><br><span>    if (rc < 0)</span><br><span>@@ -777,7 +800,7 @@</span><br><span>  *  \param[in] conn_dst associated destination connection</span><br><span>  *  \returns 0 on success, -1 on ERROR */</span><br><span> int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,</span><br><span style="color: hsl(0, 100%, 40%);">-             char *buf, int len, struct mgcp_conn_rtp *conn_src,</span><br><span style="color: hsl(120, 100%, 40%);">+           struct msgb *msg, struct mgcp_conn_rtp *conn_src,</span><br><span>            struct mgcp_conn_rtp *conn_dst)</span><br><span> {</span><br><span>   /*! When no destination connection is available (e.g. when only one</span><br><span>@@ -789,6 +812,7 @@</span><br><span>    struct mgcp_rtp_state *rtp_state;</span><br><span>    char *dest_name;</span><br><span>     int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       int len;</span><br><span> </span><br><span>         OSMO_ASSERT(conn_src);</span><br><span>       OSMO_ASSERT(conn_dst);</span><br><span>@@ -812,7 +836,7 @@</span><br><span>          * should not occur if transcoding is consequently avoided. Until</span><br><span>     * we have transcoding support in osmo-mgw we can not resolve this. */</span><br><span>       if (is_rtp) {</span><br><span style="color: hsl(0, 100%, 40%);">-           rc = mgcp_patch_pt(conn_src, conn_dst, buf, len);</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = mgcp_patch_pt(conn_src, conn_dst, msg);</span><br><span>                 if (rc < 0) {</span><br><span>                     LOGPENDP(endp, DRTP, LOGL_DEBUG,</span><br><span>                              "can not patch PT because no suitable egress codec was found.\n");</span><br><span>@@ -837,27 +861,27 @@</span><br><span>        } else if (is_rtp) {</span><br><span>                 int cont;</span><br><span>            int nbytes = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-         int buflen = len;</span><br><span style="color: hsl(120, 100%, 40%);">+             int buflen = msg->len;</span><br><span>            do {</span><br><span>                         /* Run transcoder */</span><br><span>                         cont = endp->cfg->rtp_processing_cb(endp, rtp_end,</span><br><span style="color: hsl(0, 100%, 40%);">-                                                            buf, &buflen,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                     (char*)msg->data, &buflen,</span><br><span>                                                            RTP_BUF_SIZE);</span><br><span>                   if (cont < 0)</span><br><span>                             break;</span><br><span> </span><br><span>                   if (addr)</span><br><span>                            mgcp_patch_and_count(endp, rtp_state, rtp_end,</span><br><span style="color: hsl(0, 100%, 40%);">-                                               addr, buf, buflen);</span><br><span style="color: hsl(120, 100%, 40%);">+                                                   addr, msg);</span><br><span> </span><br><span>                         if (amr_oa_bwe_convert_indicated(conn_dst->end.codec)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                             amr_oa_bwe_convert(endp, buf, &buflen,</span><br><span style="color: hsl(120, 100%, 40%);">+                            amr_oa_bwe_convert(endp, (char*)msg->data, &buflen,</span><br><span>                                              conn_dst->end.codec->param.amr_octet_aligned);</span><br><span>                      }</span><br><span>                    else if (rtp_end->rfc5993_hr_convert</span><br><span>                          && strcmp(conn_src->end.codec->subtype_name,</span><br><span>                                     "GSM-HR-08") == 0)</span><br><span style="color: hsl(0, 100%, 40%);">-                              rfc5993_hr_convert(endp, buf, &buflen);</span><br><span style="color: hsl(120, 100%, 40%);">+                           rfc5993_hr_convert(endp, (char*)msg->data, &buflen);</span><br><span> </span><br><span>                      LOGPENDP(endp, DRTP, LOGL_DEBUG,</span><br><span>                              "process/send to %s %s "</span><br><span>@@ -868,8 +892,9 @@</span><br><span> </span><br><span>                        /* Forward a copy of the RTP data to a debug ip/port */</span><br><span>                      forward_data(rtp_end->rtp.fd, &conn_src->tap_out,</span><br><span style="color: hsl(0, 100%, 40%);">-                                  buf, buflen);</span><br><span style="color: hsl(120, 100%, 40%);">+                                 msg);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#if 0</span><br><span>                        /* FIXME: HACK HACK HACK. See OS#2459.</span><br><span>                        * The ip.access nano3G needs the first RTP payload's first two bytes to read hex</span><br><span>                         * 'e400', or it will reject the RAB assignment. It seems to not harm other femto</span><br><span>@@ -877,7 +902,7 @@</span><br><span>                       */</span><br><span>                  if (!rtp_state->patched_first_rtp_payload</span><br><span>                             && conn_src->conn->mode == MGCP_CONN_LOOPBACK) {</span><br><span style="color: hsl(0, 100%, 40%);">-                              uint8_t *data = (uint8_t *) & buf[12];</span><br><span style="color: hsl(120, 100%, 40%);">+                            uint8_t *data = msg->data + 12;</span><br><span>                           if (data[0] == 0xe0) {</span><br><span>                                       data[0] = 0xe4;</span><br><span>                                      data[1] = 0x00;</span><br><span>@@ -887,10 +912,13 @@</span><br><span>                                               " to fake an IuUP Initialization Ack\n");</span><br><span>                                 }</span><br><span>                    }</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-                   len = mgcp_udp_send(rtp_end->rtp.fd,</span><br><span style="color: hsl(0, 100%, 40%);">-                                     &rtp_end->addr,</span><br><span style="color: hsl(0, 100%, 40%);">-                                          rtp_end->rtp_port, buf, buflen);</span><br><span style="color: hsl(120, 100%, 40%);">+                       if (conn_dst->iuup)</span><br><span style="color: hsl(120, 100%, 40%);">+                                len = osmo_iuup_cn_tx_payload(conn_dst->iuup, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+                        else</span><br><span style="color: hsl(120, 100%, 40%);">+                          len = mgcp_udp_send(rtp_end->rtp.fd, &rtp_end->addr, rtp_end->rtp_port,</span><br><span style="color: hsl(120, 100%, 40%);">+                                              (char*)msg->data, msg->len);</span><br><span> </span><br><span>                   if (len <= 0)</span><br><span>                             return len;</span><br><span>@@ -911,7 +939,7 @@</span><br><span> </span><br><span>                len = mgcp_udp_send(rtp_end->rtcp.fd,</span><br><span>                                 &rtp_end->addr,</span><br><span style="color: hsl(0, 100%, 40%);">-                                  rtp_end->rtcp_port, buf, len);</span><br><span style="color: hsl(120, 100%, 40%);">+                             rtp_end->rtcp_port, (char*)msg->data, msg->len);</span><br><span> </span><br><span>            rate_ctr_inc(&conn_dst->rate_ctr_group->ctr[RTP_PACKETS_TX_CTR]);</span><br><span>          rate_ctr_add(&conn_dst->rate_ctr_group->ctr[RTP_OCTETS_TX_CTR], len);</span><br><span>@@ -922,45 +950,6 @@</span><br><span>       return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/* Helper function for mgcp_recv(),</span><br><span style="color: hsl(0, 100%, 40%);">-   Receive one RTP Packet + Originating address from file descriptor */</span><br><span style="color: hsl(0, 100%, 40%);">-static int receive_from(struct mgcp_endpoint *endp, int fd,</span><br><span style="color: hsl(0, 100%, 40%);">-                 struct sockaddr_in *addr, char *buf, int bufsize)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-      int rc;</span><br><span style="color: hsl(0, 100%, 40%);">- socklen_t slen = sizeof(*addr);</span><br><span style="color: hsl(0, 100%, 40%);">- struct sockaddr_in addr_sink;</span><br><span style="color: hsl(0, 100%, 40%);">-   char buf_sink[RTP_BUF_SIZE];</span><br><span style="color: hsl(0, 100%, 40%);">-    bool tossed = false;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    if (!addr)</span><br><span style="color: hsl(0, 100%, 40%);">-              addr = &addr_sink;</span><br><span style="color: hsl(0, 100%, 40%);">-  if (!buf) {</span><br><span style="color: hsl(0, 100%, 40%);">-             tossed = true;</span><br><span style="color: hsl(0, 100%, 40%);">-          buf = buf_sink;</span><br><span style="color: hsl(0, 100%, 40%);">-         bufsize = sizeof(buf_sink);</span><br><span style="color: hsl(0, 100%, 40%);">-     }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       rc = recvfrom(fd, buf, bufsize, 0, (struct sockaddr *)addr, &slen);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- LOGPENDP(endp, DRTP, LOGL_DEBUG,</span><br><span style="color: hsl(0, 100%, 40%);">-             "receiving %u bytes length packet from %s:%u ...\n",</span><br><span style="color: hsl(0, 100%, 40%);">-          rc, inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (rc < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                LOGPENDP(endp, DRTP, LOGL_ERROR,</span><br><span style="color: hsl(0, 100%, 40%);">-                         "failed to receive packet, errno: %d/%s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                   errno, strerror(errno));</span><br><span style="color: hsl(0, 100%, 40%);">-               return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (tossed) {</span><br><span style="color: hsl(0, 100%, 40%);">-           LOGPENDP(endp, DRTP, LOGL_ERROR, "packet tossed\n");</span><br><span style="color: hsl(0, 100%, 40%);">-  }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       return rc;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> /* Check if the origin (addr) matches the address/port data of the RTP</span><br><span>  * connections. */</span><br><span> static int check_rtp_origin(struct mgcp_conn_rtp *conn,</span><br><span>@@ -1053,7 +1042,7 @@</span><br><span> </span><br><span> /* Do some basic checks to make sure that the RTCP packets we are going to</span><br><span>  * process are not complete garbage */</span><br><span style="color: hsl(0, 100%, 40%);">-static int check_rtcp(char *buf, unsigned int buf_size)</span><br><span style="color: hsl(120, 100%, 40%);">+static int check_rtcp(struct mgcp_conn_rtp *conn_src, struct msgb *msg)</span><br><span> {</span><br><span>      struct rtcp_hdr *hdr;</span><br><span>        unsigned int len;</span><br><span>@@ -1061,33 +1050,45 @@</span><br><span> </span><br><span>      /* RTPC packets that are just a header without data do not make</span><br><span>       * any sense. */</span><br><span style="color: hsl(0, 100%, 40%);">-        if (buf_size < sizeof(struct rtcp_hdr))</span><br><span style="color: hsl(120, 100%, 40%);">+    if (msg->len < sizeof(struct rtcp_hdr)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               LOG_CONN_RTP(conn_src, LOGL_ERROR, "RTCP packet too short (%u < %zu)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                      msg->len, sizeof(struct rtcp_hdr));</span><br><span>          return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span> </span><br><span>        /* Make sure that the length of the received packet does not exceed</span><br><span>   * the available buffer size */</span><br><span style="color: hsl(0, 100%, 40%);">- hdr = (struct rtcp_hdr *)buf;</span><br><span style="color: hsl(120, 100%, 40%);">+ hdr = (struct rtcp_hdr *)msg->data;</span><br><span>       len = (osmo_ntohs(hdr->length) + 1) * 4;</span><br><span style="color: hsl(0, 100%, 40%);">-     if (len > buf_size)</span><br><span style="color: hsl(120, 100%, 40%);">+        if (len > msg->len) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOG_CONN_RTP(conn_src, LOGL_ERROR, "RTCP header length exceeds packet size (%u > %u)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                      len, msg->len);</span><br><span>              return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span> </span><br><span>        /* Make sure we accept only packets that have a proper packet type set</span><br><span>        * See also: http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml */</span><br><span>  type = hdr->type;</span><br><span style="color: hsl(0, 100%, 40%);">-    if ((type < 192 || type > 195) && (type < 200 || type > 213))</span><br><span style="color: hsl(120, 100%, 40%);">+     if ((type < 192 || type > 195) && (type < 200 || type > 213)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOG_CONN_RTP(conn_src, LOGL_ERROR, "RTCP header: invalid type: %u\n", type);</span><br><span>               return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span> </span><br><span>        return 0;</span><br><span> }</span><br><span> </span><br><span> /* Do some basic checks to make sure that the RTP packets we are going to</span><br><span>  * process are not complete garbage */</span><br><span style="color: hsl(0, 100%, 40%);">-static int check_rtp(char *buf, unsigned int buf_size)</span><br><span style="color: hsl(120, 100%, 40%);">+static int check_rtp(struct mgcp_conn_rtp *conn_src, struct msgb *msg)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-    /* RTP packets that are just a header without data do not make</span><br><span style="color: hsl(0, 100%, 40%);">-   * any sense. */</span><br><span style="color: hsl(0, 100%, 40%);">-        if (buf_size < sizeof(struct rtp_hdr))</span><br><span style="color: hsl(0, 100%, 40%);">-               return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       size_t min_size = sizeof(struct rtp_hdr);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (conn_src->iuup)</span><br><span style="color: hsl(120, 100%, 40%);">+                min_size += sizeof(struct osmo_iuup_hdr_data);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (msg->len < min_size) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOG_CONN_RTP(conn_src, LOGL_ERROR, "RTP packet too short (%u < %zu)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                       msg->len, min_size);</span><br><span style="color: hsl(120, 100%, 40%);">+          return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span> </span><br><span>        /* FIXME: Add more checks, the reason why we do not check more than</span><br><span>   * the length is because we currently handle IUUP packets as RTP</span><br><span>@@ -1098,86 +1099,14 @@</span><br><span>   return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/* Receive RTP data from a specified source connection and dispatch it to a</span><br><span style="color: hsl(0, 100%, 40%);">- * destination connection. */</span><br><span style="color: hsl(0, 100%, 40%);">-static int mgcp_recv(int *proto, struct sockaddr_in *addr, char *buf,</span><br><span style="color: hsl(0, 100%, 40%);">-              unsigned int buf_size, struct osmo_fd *fd)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-        struct mgcp_endpoint *endp;</span><br><span style="color: hsl(0, 100%, 40%);">-     struct mgcp_conn_rtp *conn;</span><br><span style="color: hsl(0, 100%, 40%);">-     struct mgcp_trunk_config *tcfg;</span><br><span style="color: hsl(0, 100%, 40%);">- int rc;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- conn = (struct mgcp_conn_rtp*) fd->data;</span><br><span style="color: hsl(0, 100%, 40%);">-     endp = conn->conn->endp;</span><br><span style="color: hsl(0, 100%, 40%);">-  tcfg = endp->tcfg;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   LOGPCONN(conn->conn, DRTP, LOGL_DEBUG, "receiving RTP/RTCP packet...\n");</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  rc = receive_from(endp, fd->fd, addr, buf, buf_size);</span><br><span style="color: hsl(0, 100%, 40%);">-        if (rc <= 0)</span><br><span style="color: hsl(0, 100%, 40%);">-         return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      /* FIXME: The way how we detect the protocol looks odd. We should look</span><br><span style="color: hsl(0, 100%, 40%);">-   * into the packet header. Also we should introduce a packet type</span><br><span style="color: hsl(0, 100%, 40%);">-        * MGCP_PROTO_IUUP because currently we handle IUUP packets like RTP</span><br><span style="color: hsl(0, 100%, 40%);">-     * packets which is problematic. */</span><br><span style="color: hsl(0, 100%, 40%);">-     *proto = fd == &conn->end.rtp ? MGCP_PROTO_RTP : MGCP_PROTO_RTCP;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        if (*proto == MGCP_PROTO_RTP) {</span><br><span style="color: hsl(0, 100%, 40%);">-         if (check_rtp(buf, rc) < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        LOGPCONN(conn->conn, DRTP, LOGL_ERROR,</span><br><span style="color: hsl(0, 100%, 40%);">-                                "invalid RTP packet received -- packet tossed\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                   return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-              }</span><br><span style="color: hsl(0, 100%, 40%);">-       } else if (*proto == MGCP_PROTO_RTCP) {</span><br><span style="color: hsl(0, 100%, 40%);">-         if (check_rtcp(buf, rc) < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                       LOGPCONN(conn->conn, DRTP, LOGL_ERROR,</span><br><span style="color: hsl(0, 100%, 40%);">-                                "invalid RTCP packet received -- packet tossed\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                  return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-              }</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       LOGPCONN(conn->conn, DRTP, LOGL_DEBUG, "");</span><br><span style="color: hsl(0, 100%, 40%);">-        LOGPC(DRTP, LOGL_DEBUG, "receiving from %s %s %d\n",</span><br><span style="color: hsl(0, 100%, 40%);">-        conn->conn->name, inet_ntoa(addr->sin_addr),</span><br><span style="color: hsl(0, 100%, 40%);">-           ntohs(addr->sin_port));</span><br><span style="color: hsl(0, 100%, 40%);">-        LOGPENDP(endp, DRTP, LOGL_DEBUG, "conn:%s\n", mgcp_conn_dump(conn->conn));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* Check if the origin of the RTP packet seems plausible */</span><br><span style="color: hsl(0, 100%, 40%);">-     if (tcfg->rtp_accept_all == 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-             if (check_rtp_origin(conn, addr) != 0)</span><br><span style="color: hsl(0, 100%, 40%);">-                  return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* Filter out dummy message */</span><br><span style="color: hsl(0, 100%, 40%);">-  if (rc == 1 && buf[0] == MGCP_DUMMY_LOAD) {</span><br><span style="color: hsl(0, 100%, 40%);">-             LOGPCONN(conn->conn, DRTP, LOGL_NOTICE,</span><br><span style="color: hsl(0, 100%, 40%);">-                       "dummy message received\n");</span><br><span style="color: hsl(0, 100%, 40%);">-         LOGPCONN(conn->conn, DRTP, LOGL_ERROR,</span><br><span style="color: hsl(0, 100%, 40%);">-                        "packet tossed\n");</span><br><span style="color: hsl(0, 100%, 40%);">-          return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* Increment RX statistics */</span><br><span style="color: hsl(0, 100%, 40%);">-   rate_ctr_inc(&conn->rate_ctr_group->ctr[RTP_PACKETS_RX_CTR]);</span><br><span style="color: hsl(0, 100%, 40%);">- rate_ctr_add(&conn->rate_ctr_group->ctr[RTP_OCTETS_RX_CTR], rc);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      /* Forward a copy of the RTP data to a debug ip/port */</span><br><span style="color: hsl(0, 100%, 40%);">- forward_data(fd->fd, &conn->tap_in, buf, rc);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- return rc;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> /* Send RTP data. Possible options are standard RTP packet</span><br><span>  * transmission or trsmission via an osmux connection */</span><br><span style="color: hsl(0, 100%, 40%);">-static int mgcp_send_rtp(int proto, struct sockaddr_in *addr, char *buf,</span><br><span style="color: hsl(0, 100%, 40%);">-                    unsigned int buf_size,</span><br><span style="color: hsl(0, 100%, 40%);">-                  struct mgcp_conn_rtp *conn_src,</span><br><span style="color: hsl(0, 100%, 40%);">-                         struct mgcp_conn_rtp *conn_dst)</span><br><span style="color: hsl(120, 100%, 40%);">+static int mgcp_send_rtp(struct mgcp_conn_rtp *conn_dst, struct msgb *msg)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-       struct mgcp_endpoint *endp;</span><br><span style="color: hsl(0, 100%, 40%);">-     endp = conn_src->conn->endp;</span><br><span style="color: hsl(120, 100%, 40%);">+    enum rtp_proto proto = OSMO_RTP_MSG_CTX(msg)->proto;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct mgcp_conn_rtp *conn_src = OSMO_RTP_MSG_CTX(msg)->conn_src;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct sockaddr_in *from_addr = OSMO_RTP_MSG_CTX(msg)->from_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct mgcp_endpoint *endp = conn_src->conn->endp;</span><br><span> </span><br><span>         LOGPENDP(endp, DRTP, LOGL_DEBUG, "destin conn:%s\n",</span><br><span>                mgcp_conn_dump(conn_dst->conn));</span><br><span>@@ -1196,13 +1125,13 @@</span><br><span>                        "endpoint type is MGCP_RTP_DEFAULT, "</span><br><span>                      "using mgcp_send() to forward data directly\n");</span><br><span>          return mgcp_send(endp, proto == MGCP_PROTO_RTP,</span><br><span style="color: hsl(0, 100%, 40%);">-                          addr, buf, buf_size, conn_src, conn_dst);</span><br><span style="color: hsl(120, 100%, 40%);">+                             from_addr, msg, conn_src, conn_dst);</span><br><span>        case MGCP_OSMUX_BSC_NAT:</span><br><span>     case MGCP_OSMUX_BSC:</span><br><span>                 LOGPENDP(endp, DRTP, LOGL_DEBUG,</span><br><span>                      "endpoint type is MGCP_OSMUX_BSC_NAT, "</span><br><span>                    "using osmux_xfrm_to_osmux() to forward data through OSMUX\n");</span><br><span style="color: hsl(0, 100%, 40%);">-              return osmux_xfrm_to_osmux(buf, buf_size, conn_dst);</span><br><span style="color: hsl(120, 100%, 40%);">+          return osmux_xfrm_to_osmux((char*)msg->data, msg->len, conn_dst);</span><br><span>      }</span><br><span> </span><br><span>        /* If the data has not been handled/forwarded until here, it will</span><br><span>@@ -1220,10 +1149,12 @@</span><br><span>  *  \param[in] buf_size size data length of buf</span><br><span>  *  \param[in] conn originating connection</span><br><span>  *  \returns 0 on success, -1 on ERROR */</span><br><span style="color: hsl(0, 100%, 40%);">-int mgcp_dispatch_rtp_bridge_cb(int proto, struct sockaddr_in *addr, char *buf,</span><br><span style="color: hsl(0, 100%, 40%);">-                                unsigned int buf_size, struct mgcp_conn *conn)</span><br><span style="color: hsl(120, 100%, 40%);">+int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+        struct mgcp_conn_rtp *conn_src = OSMO_RTP_MSG_CTX(msg)->conn_src;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct mgcp_conn *conn = conn_src->conn;</span><br><span>  struct mgcp_conn *conn_dst;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct sockaddr_in *from_addr = OSMO_RTP_MSG_CTX(msg)->from_addr;</span><br><span> </span><br><span>     /*! NOTE: This callback function implements the endpoint specific</span><br><span>     *  dispatch bahviour of an rtp bridge/proxy endpoint. It is assumed</span><br><span>@@ -1242,11 +1173,10 @@</span><br><span>                * address data from the UDP packet header to patch the</span><br><span>               * outgoing address in connection on the fly */</span><br><span>              if (conn->u.rtp.end.rtp_port == 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                 conn->u.rtp.end.addr = addr->sin_addr;</span><br><span style="color: hsl(0, 100%, 40%);">-                    conn->u.rtp.end.rtp_port = addr->sin_port;</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>                }</span><br><span style="color: hsl(0, 100%, 40%);">-               return mgcp_send_rtp(proto, addr, buf,</span><br><span style="color: hsl(0, 100%, 40%);">-                               buf_size, &conn->u.rtp, &conn->u.rtp);</span><br><span style="color: hsl(120, 100%, 40%);">+             return mgcp_send_rtp(conn_src, msg);</span><br><span>         }</span><br><span> </span><br><span>        /* Find a destination connection. */</span><br><span>@@ -1278,9 +1208,7 @@</span><br><span>         }</span><br><span> </span><br><span>        /* Dispatch RTP packet to destination RTP connection */</span><br><span style="color: hsl(0, 100%, 40%);">- return mgcp_send_rtp(proto, addr, buf,</span><br><span style="color: hsl(0, 100%, 40%);">-                       buf_size, &conn->u.rtp, &conn_dst->u.rtp);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+ return mgcp_send_rtp(&conn_dst->u.rtp, 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>@@ -1302,6 +1230,76 @@</span><br><span>     }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static bool is_dummy_msg(enum rtp_proto proto, struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       return msg->len == 1 && msg->data[0] == MGCP_DUMMY_LOAD;</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%);">+struct pdu_ctx {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct sockaddr_in *from_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct mgcp_conn_rtp *conn_src;</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%);">+/* IuUP CN node has stripped an IuUP header and forwards RTP data to distribute to the peers. */</span><br><span style="color: hsl(120, 100%, 40%);">+int iuup_rx_payload(struct msgb *msg, void *node_priv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct mgcp_conn_rtp *conn_src = OSMO_RTP_MSG_CTX(msg)->conn_src;</span><br><span style="color: hsl(120, 100%, 40%);">+  LOG_CONN_RTP(conn_src, LOGL_DEBUG, "iuup_rx_payload(%u bytes)\n", msg->len);</span><br><span style="color: hsl(120, 100%, 40%);">+     return rx_rtp(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%);">+/* IuUP CN node has composed a message that contains an IuUP header and asks us to send to the IuUP peer.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int iuup_tx_msg(struct msgb *msg, void *node_priv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       const struct in_addr zero_addr = {};</span><br><span style="color: hsl(120, 100%, 40%);">+  struct mgcp_conn_rtp *conn_src = OSMO_RTP_MSG_CTX(msg)->conn_src;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct mgcp_conn_rtp *conn_dst = node_priv;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct sockaddr_in *from_addr = OSMO_RTP_MSG_CTX(msg)->from_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct mgcp_rtp_end *rtp_end = &conn_dst->end;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct in_addr to_addr = rtp_end->addr;</span><br><span style="color: hsl(120, 100%, 40%);">+    uint16_t to_port = rtp_end->rtp_port;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (conn_src == conn_dst</span><br><span style="color: hsl(120, 100%, 40%);">+          && !memcmp(&zero_addr, &to_addr, sizeof(zero_addr)) && !to_port) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOG_CONN_RTP(conn_dst, LOGL_DEBUG, "iuup_tx_msg(): direct IuUP reply\n");</span><br><span style="color: hsl(120, 100%, 40%);">+           /* IuUP wants to send a message back to the same peer that sent an RTP package, but there</span><br><span style="color: hsl(120, 100%, 40%);">+              * is no address configured for that peer yet. It is probably an IuUP Initialization ACK</span><br><span style="color: hsl(120, 100%, 40%);">+               * reply. Use the sender address to send the reply.</span><br><span style="color: hsl(120, 100%, 40%);">+            *</span><br><span style="color: hsl(120, 100%, 40%);">+             * During 3G RAB Assignment, a 3G cell might first probe the MGW and expect an IuUP</span><br><span style="color: hsl(120, 100%, 40%);">+            * Initialization ACK before it replies to the MSC with a successful RAB Assignment; only</span><br><span style="color: hsl(120, 100%, 40%);">+              * after that reply does MSC officially know which RTP address+port the 3G cell wants to</span><br><span style="color: hsl(120, 100%, 40%);">+               * use and can tell this MGW about it, so this "loopback" is, for some 3G cells, the only</span><br><span style="color: hsl(120, 100%, 40%);">+            * chance we have to get a successful RAB Assignment done (particularly the nano3G does</span><br><span style="color: hsl(120, 100%, 40%);">+                * this). */</span><br><span style="color: hsl(120, 100%, 40%);">+          to_addr = from_addr->sin_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+             to_port = from_addr->sin_port;</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%);">+   LOG_CONN_RTP(conn_dst, LOGL_DEBUG, "iuup_tx_msg(%u bytes) to %s:%u\n", msg->len,</span><br><span style="color: hsl(120, 100%, 40%);">+              inet_ntoa(to_addr), ntohs(to_port));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return mgcp_udp_send(rtp_end->rtp.fd, &to_addr, to_port, (char*)msg->data, msg->len);</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%);">+static void iuup_init(struct mgcp_conn_rtp *conn_src)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_iuup_cn_cfg cfg = {</span><br><span style="color: hsl(120, 100%, 40%);">+               .node_priv = conn_src,</span><br><span style="color: hsl(120, 100%, 40%);">+                .rx_payload = iuup_rx_payload,</span><br><span style="color: hsl(120, 100%, 40%);">+                .tx_msg = iuup_tx_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%);">+  if (conn_src->iuup) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOG_CONN_RTP(conn_src, LOGL_NOTICE, "Rx IuUP init, but already initialized. Ignoring.\n");</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%);">+   conn_src->iuup = osmo_iuup_cn_init(conn_src->conn, &cfg, "endp_%d_conn_%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                                          ENDPOINT_NUMBER(conn_src->conn->endp), conn_src->conn->id);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Handle incoming RTP data from NET */</span><br><span> static int rtp_data_net(struct osmo_fd *fd, unsigned int what)</span><br><span> {</span><br><span>@@ -1315,23 +1313,88 @@</span><br><span>  struct mgcp_conn_rtp *conn_src;</span><br><span>      struct mgcp_endpoint *endp;</span><br><span>  struct sockaddr_in addr;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        char buf[RTP_BUF_SIZE];</span><br><span style="color: hsl(0, 100%, 40%);">- int proto;</span><br><span style="color: hsl(0, 100%, 40%);">-      int len;</span><br><span style="color: hsl(120, 100%, 40%);">+      socklen_t slen = sizeof(addr);</span><br><span style="color: hsl(120, 100%, 40%);">+        int ret;</span><br><span style="color: hsl(120, 100%, 40%);">+      enum rtp_proto proto;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_rtp_msg_ctx mc;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct msgb *msg = msgb_alloc_headroom(RTP_BUF_SIZE + OSMO_IUUP_HEADROOM,</span><br><span style="color: hsl(120, 100%, 40%);">+                                            OSMO_IUUP_HEADROOM, "RTP-rx");</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc;</span><br><span> </span><br><span>  conn_src = (struct mgcp_conn_rtp *)fd->data;</span><br><span>      OSMO_ASSERT(conn_src);</span><br><span>       endp = conn_src->conn->endp;</span><br><span>   OSMO_ASSERT(endp);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  LOGPENDP(endp, DRTP, LOGL_DEBUG, "source conn:%s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-           mgcp_conn_dump(conn_src->conn));</span><br><span style="color: hsl(120, 100%, 40%);">+  proto = (fd == &conn_src->end.rtp)? MGCP_PROTO_RTP : MGCP_PROTO_RTCP;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        /* Receive packet */</span><br><span style="color: hsl(0, 100%, 40%);">-    len = mgcp_recv(&proto, &addr, buf, sizeof(buf), fd);</span><br><span style="color: hsl(0, 100%, 40%);">-   if (len < 0)</span><br><span style="color: hsl(0, 100%, 40%);">-         return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    ret = recvfrom(fd->fd, msg->data, msg->data_len, 0, (struct sockaddr *)&addr, &slen);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (ret <= 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOG_CONN_RTP(conn_src, LOGL_ERROR, "recvfrom error: %s\n", strerror(errno));</span><br><span style="color: hsl(120, 100%, 40%);">+                rc = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+              goto out;</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%);">+   msgb_put(msg, ret);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOG_CONN_RTP(conn_src, LOGL_DEBUG, "%s: rx %u bytes from %s:%u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+               proto == MGCP_PROTO_RTP ? "RTP" : "RTPC",</span><br><span style="color: hsl(120, 100%, 40%);">+                 msg->len, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if ((proto == MGCP_PROTO_RTP && check_rtp(conn_src, msg))</span><br><span style="color: hsl(120, 100%, 40%);">+         || (proto == MGCP_PROTO_RTCP && check_rtcp(conn_src, msg))) {</span><br><span style="color: hsl(120, 100%, 40%);">+             /* Logging happened in the two check_ functions */</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+              goto out;</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 (is_dummy_msg(proto, msg)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               LOG_CONN_RTP(conn_src, LOGL_DEBUG, "rx dummy packet (dropped)\n");</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+               goto out;</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%);">+   mc = (struct osmo_rtp_msg_ctx){</span><br><span style="color: hsl(120, 100%, 40%);">+               .proto = proto,</span><br><span style="color: hsl(120, 100%, 40%);">+               .conn_src = conn_src,</span><br><span style="color: hsl(120, 100%, 40%);">+         .from_addr = &addr,</span><br><span style="color: hsl(120, 100%, 40%);">+       };</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_RTP_MSG_CTX(msg) = &mc;</span><br><span style="color: hsl(120, 100%, 40%);">+      LOG_CONN_RTP(conn_src, LOGL_DEBUG, "msg ctx: %d %p %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                OSMO_RTP_MSG_CTX(msg)->proto,</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_RTP_MSG_CTX(msg)->conn_src,</span><br><span style="color: hsl(120, 100%, 40%);">+                   osmo_hexdump((void*)OSMO_RTP_MSG_CTX(msg)->from_addr, sizeof(struct sockaddr_in)));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Increment RX statistics */</span><br><span style="color: hsl(120, 100%, 40%);">+ rate_ctr_inc(&conn_src->rate_ctr_group->ctr[RTP_PACKETS_RX_CTR]);</span><br><span style="color: hsl(120, 100%, 40%);">+   rate_ctr_add(&conn_src->rate_ctr_group->ctr[RTP_OCTETS_RX_CTR], msg->len);</span><br><span style="color: hsl(120, 100%, 40%);">+       /* FIXME: count RTP and RTCP separately, also count IuUP payload-less separately */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Forward a copy of the RTP data to a debug ip/port */</span><br><span style="color: hsl(120, 100%, 40%);">+       forward_data(fd->fd, &conn_src->tap_in, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (proto == MGCP_PROTO_RTP && osmo_iuup_is_init(msg))</span><br><span style="color: hsl(120, 100%, 40%);">+                iuup_init(conn_src);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (conn_src->iuup && proto == MGCP_PROTO_RTP)</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = osmo_iuup_cn_rx_pdu(conn_src->iuup, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+     else</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = rx_rtp(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+out:</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_free(msg);</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%);">+static int rx_rtp(struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct mgcp_conn_rtp *conn_src = OSMO_RTP_MSG_CTX(msg)->conn_src;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct sockaddr_in *from_addr = OSMO_RTP_MSG_CTX(msg)->from_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct mgcp_conn *conn = conn_src->conn;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct mgcp_trunk_config *tcfg = conn->endp->tcfg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    LOG_CONN_RTP(conn_src, LOGL_DEBUG, "rx_rtp(%u bytes)\n", msg->len);</span><br><span> </span><br><span>         mgcp_conn_watchdog_kick(conn_src->conn);</span><br><span> </span><br><span>@@ -1340,14 +1403,17 @@</span><br><span>     * define, then we check if the incoming payload matches that</span><br><span>         * expectation. */</span><br><span>   if (amr_oa_bwe_convert_indicated(conn_src->end.codec)) {</span><br><span style="color: hsl(0, 100%, 40%);">-             if (amr_oa_check(buf, len) != conn_src->end.codec->param.amr_octet_aligned)</span><br><span style="color: hsl(120, 100%, 40%);">+             if (amr_oa_check((char*)msg->data, msg->len) != conn_src->end.codec->param.amr_octet_aligned)</span><br><span>                    return -1;</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Check if the origin of the RTP packet seems plausible */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!tcfg->rtp_accept_all && check_rtp_origin(conn_src, from_addr))</span><br><span style="color: hsl(120, 100%, 40%);">+                return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         /* Execute endpoint specific implementation that handles the</span><br><span>          * dispatching of the RTP data */</span><br><span style="color: hsl(0, 100%, 40%);">-       return endp->type->dispatch_rtp_cb(proto, &addr, buf, len,</span><br><span style="color: hsl(0, 100%, 40%);">-                                       conn_src->conn);</span><br><span style="color: hsl(120, 100%, 40%);">+        return conn->endp->type->dispatch_rtp_cb(msg);</span><br><span> }</span><br><span> </span><br><span> /*! set IP Type of Service parameter.</span><br><span>diff --git a/src/libosmo-mgcp/mgcp_osmux.c b/src/libosmo-mgcp/mgcp_osmux.c</span><br><span>index 72d3b91..885e2ae 100644</span><br><span>--- a/src/libosmo-mgcp/mgcp_osmux.c</span><br><span>+++ b/src/libosmo-mgcp/mgcp_osmux.c</span><br><span>@@ -234,13 +234,8 @@</span><br><span> {</span><br><span>       struct mgcp_conn_rtp *conn = data;</span><br><span>   struct mgcp_endpoint *endp = conn->conn->endp;</span><br><span style="color: hsl(0, 100%, 40%);">-    struct sockaddr_in addr = {</span><br><span style="color: hsl(0, 100%, 40%);">-             .sin_addr = conn->end.addr,</span><br><span style="color: hsl(0, 100%, 40%);">-          .sin_port = conn->end.rtp_port,</span><br><span style="color: hsl(0, 100%, 40%);">-      }; /* FIXME: not set/used in cb */</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  endp->type->dispatch_rtp_cb(MGCP_PROTO_RTP, &addr, (char *)msg->data, msg->len, conn->conn);</span><br><span style="color: hsl(120, 100%, 40%);">+       endp->type->dispatch_rtp_cb(msg);</span><br><span>      msgb_free(msg);</span><br><span> }</span><br><span> </span><br><span>diff --git a/src/osmo-mgw/mgw_main.c b/src/osmo-mgw/mgw_main.c</span><br><span>index adc1751..0b2ecce 100644</span><br><span>--- a/src/osmo-mgw/mgw_main.c</span><br><span>+++ b/src/osmo-mgw/mgw_main.c</span><br><span>@@ -244,6 +244,12 @@</span><br><span>               .color = "\033[1;30m",</span><br><span>             .enabled = 1,.loglevel = LOGL_NOTICE,</span><br><span>                },</span><br><span style="color: hsl(120, 100%, 40%);">+  [DIUUP] = {</span><br><span style="color: hsl(120, 100%, 40%);">+             .name = "DIUUP",</span><br><span style="color: hsl(120, 100%, 40%);">+            .description = "IuUP within RTP stream 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>diff --git a/tests/Makefile.am b/tests/Makefile.am</span><br><span>index 49a659f..302fa52 100644</span><br><span>--- a/tests/Makefile.am</span><br><span>+++ b/tests/Makefile.am</span><br><span>@@ -1,6 +1,7 @@</span><br><span> SUBDIRS = \</span><br><span>       mgcp_client \</span><br><span>        mgcp \</span><br><span style="color: hsl(120, 100%, 40%);">+        iuup \</span><br><span>       $(NULL)</span><br><span> </span><br><span> # The `:;' works around a Bash 3.2 bug when the output is not writeable.</span><br><span>diff --git a/tests/iuup/Makefile.am b/tests/iuup/Makefile.am</span><br><span>new file mode 100644</span><br><span>index 0000000..12806b1</span><br><span>--- /dev/null</span><br><span>+++ b/tests/iuup/Makefile.am</span><br><span>@@ -0,0 +1,45 @@</span><br><span style="color: hsl(120, 100%, 40%);">+AM_CPPFLAGS = \</span><br><span style="color: hsl(120, 100%, 40%);">+ $(all_includes) \</span><br><span style="color: hsl(120, 100%, 40%);">+     -I$(top_srcdir)/include \</span><br><span style="color: hsl(120, 100%, 40%);">+     -I$(top_srcdir) \</span><br><span style="color: hsl(120, 100%, 40%);">+     $(NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+AM_CFLAGS = \</span><br><span style="color: hsl(120, 100%, 40%);">+      -Wall \</span><br><span style="color: hsl(120, 100%, 40%);">+       -ggdb3 \</span><br><span style="color: hsl(120, 100%, 40%);">+      $(LIBOSMOCORE_CFLAGS) \</span><br><span style="color: hsl(120, 100%, 40%);">+       $(LIBOSMOVTY_CFLAGS) \</span><br><span style="color: hsl(120, 100%, 40%);">+        $(LIBOSMOGSM_CFLAGS) \</span><br><span style="color: hsl(120, 100%, 40%);">+        $(LIBOSMONETIF_CFLAGS) \</span><br><span style="color: hsl(120, 100%, 40%);">+      $(COVERAGE_CFLAGS) \</span><br><span style="color: hsl(120, 100%, 40%);">+  $(NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+AM_LDFLAGS = \</span><br><span style="color: hsl(120, 100%, 40%);">+     $(COVERAGE_LDFLAGS) \</span><br><span style="color: hsl(120, 100%, 40%);">+ $(NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+EXTRA_DIST = \</span><br><span style="color: hsl(120, 100%, 40%);">+     iuup_test.ok \</span><br><span style="color: hsl(120, 100%, 40%);">+        iuup_test.err \</span><br><span style="color: hsl(120, 100%, 40%);">+       $(NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+noinst_PROGRAMS = \</span><br><span style="color: hsl(120, 100%, 40%);">+        iuup_test \</span><br><span style="color: hsl(120, 100%, 40%);">+   $(NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+iuup_test_SOURCES = \</span><br><span style="color: hsl(120, 100%, 40%);">+      iuup_test.c \</span><br><span style="color: hsl(120, 100%, 40%);">+ $(NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+iuup_test_LDADD = \</span><br><span style="color: hsl(120, 100%, 40%);">+        $(top_builddir)/src/libosmo-mgcp/libosmo-mgcp.a \</span><br><span style="color: hsl(120, 100%, 40%);">+     $(LIBOSMOCORE_LIBS) \</span><br><span style="color: hsl(120, 100%, 40%);">+ $(LIBOSMOVTY_LIBS) \</span><br><span style="color: hsl(120, 100%, 40%);">+  $(LIBOSMOGSM_LIBS) \</span><br><span style="color: hsl(120, 100%, 40%);">+  $(LIBRARY_DL) \</span><br><span style="color: hsl(120, 100%, 40%);">+       $(LIBOSMONETIF_LIBS) \</span><br><span style="color: hsl(120, 100%, 40%);">+        -lm  \</span><br><span style="color: hsl(120, 100%, 40%);">+        $(NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+update_exp:</span><br><span style="color: hsl(120, 100%, 40%);">+        $(builddir)/iuup_test >$(srcdir)/iuup_test.ok 2>$(srcdir)/iuup_test.err</span><br><span>diff --git a/tests/iuup/iuup_test.c b/tests/iuup/iuup_test.c</span><br><span>new file mode 100644</span><br><span>index 0000000..e6f2ca5</span><br><span>--- /dev/null</span><br><span>+++ b/tests/iuup/iuup_test.c</span><br><span>@@ -0,0 +1,156 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <string.h></span><br><span style="color: hsl(120, 100%, 40%);">+</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/core/application.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mgcp/iuup_cn_node.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mgcp/iuup_protocol.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void *ctx = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const char *dump(struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       return osmo_hexdump_nospc(msg->data, msg->len);</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%);">+struct msgb *msgb_from_hex(const char *label, const char *hex)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *msg = msgb_alloc_headroom(4096 + OSMO_IUUP_HEADROOM,</span><br><span style="color: hsl(120, 100%, 40%);">+                                            OSMO_IUUP_HEADROOM, label);</span><br><span style="color: hsl(120, 100%, 40%);">+    unsigned char *rc;</span><br><span style="color: hsl(120, 100%, 40%);">+    msg->l2h = msg->data;</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = msgb_put(msg, osmo_hexparse(hex, msg->data, msgb_tailroom(msg)));</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(rc == msg->l2h);</span><br><span style="color: hsl(120, 100%, 40%);">+       return 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%);">+const char *expect_rx_payload = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+int rx_payload(struct msgb *msg, void *node_priv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("rx_payload() invoked by iuup_cn!\n");</span><br><span style="color: hsl(120, 100%, 40%);">+       printf("        [IuUP] -RTP->\n");</span><br><span style="color: hsl(120, 100%, 40%);">+       printf("%s\n", dump(msg));</span><br><span style="color: hsl(120, 100%, 40%);">+  printf("node_priv=%p\n", node_priv);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!expect_rx_payload) {</span><br><span style="color: hsl(120, 100%, 40%);">+             printf("ERROR: did not expect rx_payload()\n");</span><br><span style="color: hsl(120, 100%, 40%);">+             exit(-1);</span><br><span style="color: hsl(120, 100%, 40%);">+     } else if (strcmp(expect_rx_payload, dump(msg))) {</span><br><span style="color: hsl(120, 100%, 40%);">+            printf("ERROR: mismatches expected msg %s\n", expect_rx_payload);</span><br><span style="color: hsl(120, 100%, 40%);">+           exit(-1);</span><br><span style="color: hsl(120, 100%, 40%);">+     } else</span><br><span style="color: hsl(120, 100%, 40%);">+                printf("ok: matches expected msg\n");</span><br><span style="color: hsl(120, 100%, 40%);">+       expect_rx_payload = NULL;</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%);">+const char *expect_tx_msg = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+int tx_msg(struct msgb *msg, void *node_priv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   printf("tx_msg() invoked by iuup_cn!\n");</span><br><span style="color: hsl(120, 100%, 40%);">+   printf(" <-PDU- [IuUP]\n");</span><br><span style="color: hsl(120, 100%, 40%);">+      printf("%s\n", dump(msg));</span><br><span style="color: hsl(120, 100%, 40%);">+  printf("node_priv=%p\n", node_priv);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!expect_tx_msg) {</span><br><span style="color: hsl(120, 100%, 40%);">+         printf("ERROR: did not expect tx_msg()\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         exit(-1);</span><br><span style="color: hsl(120, 100%, 40%);">+     } else if (strcmp(expect_tx_msg, dump(msg))) {</span><br><span style="color: hsl(120, 100%, 40%);">+                printf("ERROR: mismatches expected msg %s\n", expect_tx_msg);</span><br><span style="color: hsl(120, 100%, 40%);">+               exit(-1);</span><br><span style="color: hsl(120, 100%, 40%);">+     } else</span><br><span style="color: hsl(120, 100%, 40%);">+                printf("ok: matches expected msg\n");</span><br><span style="color: hsl(120, 100%, 40%);">+       expect_tx_msg = NULL;</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%);">+static int rx_pdu(struct osmo_iuup_cn *cn, struct msgb *msg)</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%);">+       printf(" -PDU-> [IuUP]\n");</span><br><span style="color: hsl(120, 100%, 40%);">+      printf("%s\n", dump(msg));</span><br><span style="color: hsl(120, 100%, 40%);">+  rc = osmo_iuup_cn_rx_pdu(cn, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+    printf("rc=%d\n", rc);</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%);">+static int tx_payload(struct osmo_iuup_cn *cn, struct msgb *msg)</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%);">+       printf("        [IuUP] <-RTP-\n");</span><br><span style="color: hsl(120, 100%, 40%);">+       printf("%s\n", dump(msg));</span><br><span style="color: hsl(120, 100%, 40%);">+  rc = osmo_iuup_cn_tx_payload(cn, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+        printf("rc=%d\n", rc);</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%);">+void test_cn_session()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    void *node_priv = (void*)0x2342;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_iuup_cn_cfg cfg = {</span><br><span style="color: hsl(120, 100%, 40%);">+               .node_priv = node_priv,</span><br><span style="color: hsl(120, 100%, 40%);">+               .rx_payload = rx_payload,</span><br><span style="color: hsl(120, 100%, 40%);">+             .tx_msg = tx_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%);">+  struct osmo_iuup_cn *cn = osmo_iuup_cn_init(ctx, &cfg, __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(cn);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    printf("\nSend IuUP Initialization. Expecting direct tx_msg() of the Initialization Ack\n");</span><br><span style="color: hsl(120, 100%, 40%);">+        expect_tx_msg = "8060dc5219495e3f00010111" /* RTP header */</span><br><span style="color: hsl(120, 100%, 40%);">+                 "e4002400"; /* IuUP Init Ack */</span><br><span style="color: hsl(120, 100%, 40%);">+     rx_pdu(cn,</span><br><span style="color: hsl(120, 100%, 40%);">+           msgb_from_hex("IuUP-Init",</span><br><span style="color: hsl(120, 100%, 40%);">+                        "8060dc5219495e3f00010111" /* <- RTP header */</span><br><span style="color: hsl(120, 100%, 40%);">+                           "e000df99" /* <- IuUP header */</span><br><span style="color: hsl(120, 100%, 40%);">+                          "160051673c01270000820000001710000100" /* IuUP params */));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define RTP_HEADER "8060944c6256042c00010102"</span><br><span style="color: hsl(120, 100%, 40%);">+#define IUUP_HEADER "0100e2b3"</span><br><span style="color: hsl(120, 100%, 40%);">+#define RTP_PAYLOAD "6cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0"</span><br><span style="color: hsl(120, 100%, 40%);">+       printf("\nReceive payload encapsulated in IuUP. Expecting rx_payload() of just RTP packet\n");</span><br><span style="color: hsl(120, 100%, 40%);">+      printf("i.e. should strip away " IUUP_HEADER "\n");</span><br><span style="color: hsl(120, 100%, 40%);">+       expect_rx_payload = RTP_HEADER "f03c" RTP_PAYLOAD;</span><br><span style="color: hsl(120, 100%, 40%);">+  rx_pdu(cn,</span><br><span style="color: hsl(120, 100%, 40%);">+           msgb_from_hex("IuUP-Data",</span><br><span style="color: hsl(120, 100%, 40%);">+                        RTP_HEADER IUUP_HEADER RTP_PAYLOAD));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  printf("\nTransmit RTP. Expecting tx_msg() with inserted IuUP header\n");</span><br><span style="color: hsl(120, 100%, 40%);">+   expect_tx_msg = RTP_HEADER "000002b3" RTP_PAYLOAD;</span><br><span style="color: hsl(120, 100%, 40%);">+  tx_payload(cn,</span><br><span style="color: hsl(120, 100%, 40%);">+                   msgb_from_hex("RTP data", RTP_HEADER "f03c" RTP_PAYLOAD));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   printf("\nMore RTP, each time the Frame Nr advances, causing a new header CRC.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ expect_tx_msg = RTP_HEADER "0100e2b3" RTP_PAYLOAD;</span><br><span style="color: hsl(120, 100%, 40%);">+  tx_payload(cn,</span><br><span style="color: hsl(120, 100%, 40%);">+                   msgb_from_hex("RTP data", RTP_HEADER "f03c" RTP_PAYLOAD));</span><br><span style="color: hsl(120, 100%, 40%);">+     expect_tx_msg = RTP_HEADER "02007eb3" RTP_PAYLOAD;</span><br><span style="color: hsl(120, 100%, 40%);">+  tx_payload(cn,</span><br><span style="color: hsl(120, 100%, 40%);">+                   msgb_from_hex("RTP data", RTP_HEADER "f03c" RTP_PAYLOAD));</span><br><span style="color: hsl(120, 100%, 40%);">+     expect_tx_msg = RTP_HEADER "03009eb3" RTP_PAYLOAD;</span><br><span style="color: hsl(120, 100%, 40%);">+  tx_payload(cn,</span><br><span style="color: hsl(120, 100%, 40%);">+                   msgb_from_hex("RTP data", RTP_HEADER "f03c" RTP_PAYLOAD));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   printf("All done.\n");</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%);">+static const struct log_info_cat log_categories[] = {</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 struct log_info log_info = {</span><br><span style="color: hsl(120, 100%, 40%);">+        .cat = log_categories,</span><br><span style="color: hsl(120, 100%, 40%);">+        .num_cat = ARRAY_SIZE(log_categories),</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%);">+int main(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       ctx = talloc_named_const(NULL, 0, __FILE__);</span><br><span style="color: hsl(120, 100%, 40%);">+  void *msgb_ctx = msgb_talloc_ctx_init(ctx, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_init_logging2(ctx, &log_info);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     test_cn_session();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  talloc_free(msgb_ctx);</span><br><span style="color: hsl(120, 100%, 40%);">+        return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/tests/iuup/iuup_test.err b/tests/iuup/iuup_test.err</span><br><span>new file mode 100644</span><br><span>index 0000000..e69de29</span><br><span>--- /dev/null</span><br><span>+++ b/tests/iuup/iuup_test.err</span><br><span>diff --git a/tests/iuup/iuup_test.ok b/tests/iuup/iuup_test.ok</span><br><span>new file mode 100644</span><br><span>index 0000000..8c473d6</span><br><span>--- /dev/null</span><br><span>+++ b/tests/iuup/iuup_test.ok</span><br><span>@@ -0,0 +1,58 @@</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Send IuUP Initialization. Expecting direct tx_msg() of the Initialization Ack</span><br><span style="color: hsl(120, 100%, 40%);">+ -PDU-> [IuUP]</span><br><span style="color: hsl(120, 100%, 40%);">+8060dc5219495e3f00010111e000df99160051673c01270000820000001710000100</span><br><span style="color: hsl(120, 100%, 40%);">+tx_msg() invoked by iuup_cn!</span><br><span style="color: hsl(120, 100%, 40%);">+ <-PDU- [IuUP]</span><br><span style="color: hsl(120, 100%, 40%);">+8060dc5219495e3f00010111e4002400</span><br><span style="color: hsl(120, 100%, 40%);">+node_priv=0x2342</span><br><span style="color: hsl(120, 100%, 40%);">+ok: matches expected msg</span><br><span style="color: hsl(120, 100%, 40%);">+rc=0</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Receive payload encapsulated in IuUP. Expecting rx_payload() of just RTP packet</span><br><span style="color: hsl(120, 100%, 40%);">+i.e. should strip away 0100e2b3</span><br><span style="color: hsl(120, 100%, 40%);">+ -PDU-> [IuUP]</span><br><span style="color: hsl(120, 100%, 40%);">+8060944c6256042c000101020100e2b36cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0</span><br><span style="color: hsl(120, 100%, 40%);">+rx_payload() invoked by iuup_cn!</span><br><span style="color: hsl(120, 100%, 40%);">+        [IuUP] -RTP-></span><br><span style="color: hsl(120, 100%, 40%);">+8060944c6256042c00010102f03c6cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0</span><br><span style="color: hsl(120, 100%, 40%);">+node_priv=0x2342</span><br><span style="color: hsl(120, 100%, 40%);">+ok: matches expected msg</span><br><span style="color: hsl(120, 100%, 40%);">+rc=0</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Transmit RTP. Expecting tx_msg() with inserted IuUP header</span><br><span style="color: hsl(120, 100%, 40%);">+        [IuUP] <-RTP-</span><br><span style="color: hsl(120, 100%, 40%);">+8060944c6256042c00010102f03c6cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0</span><br><span style="color: hsl(120, 100%, 40%);">+tx_msg() invoked by iuup_cn!</span><br><span style="color: hsl(120, 100%, 40%);">+ <-PDU- [IuUP]</span><br><span style="color: hsl(120, 100%, 40%);">+8060944c6256042c00010102000002b36cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0</span><br><span style="color: hsl(120, 100%, 40%);">+node_priv=0x2342</span><br><span style="color: hsl(120, 100%, 40%);">+ok: matches expected msg</span><br><span style="color: hsl(120, 100%, 40%);">+rc=0</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+More RTP, each time the Frame Nr advances, causing a new header CRC.</span><br><span style="color: hsl(120, 100%, 40%);">+        [IuUP] <-RTP-</span><br><span style="color: hsl(120, 100%, 40%);">+8060944c6256042c00010102f03c6cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0</span><br><span style="color: hsl(120, 100%, 40%);">+tx_msg() invoked by iuup_cn!</span><br><span style="color: hsl(120, 100%, 40%);">+ <-PDU- [IuUP]</span><br><span style="color: hsl(120, 100%, 40%);">+8060944c6256042c000101020100e2b36cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0</span><br><span style="color: hsl(120, 100%, 40%);">+node_priv=0x2342</span><br><span style="color: hsl(120, 100%, 40%);">+ok: matches expected msg</span><br><span style="color: hsl(120, 100%, 40%);">+rc=0</span><br><span style="color: hsl(120, 100%, 40%);">+        [IuUP] <-RTP-</span><br><span style="color: hsl(120, 100%, 40%);">+8060944c6256042c00010102f03c6cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0</span><br><span style="color: hsl(120, 100%, 40%);">+tx_msg() invoked by iuup_cn!</span><br><span style="color: hsl(120, 100%, 40%);">+ <-PDU- [IuUP]</span><br><span style="color: hsl(120, 100%, 40%);">+8060944c6256042c0001010202007eb36cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0</span><br><span style="color: hsl(120, 100%, 40%);">+node_priv=0x2342</span><br><span style="color: hsl(120, 100%, 40%);">+ok: matches expected msg</span><br><span style="color: hsl(120, 100%, 40%);">+rc=0</span><br><span style="color: hsl(120, 100%, 40%);">+        [IuUP] <-RTP-</span><br><span style="color: hsl(120, 100%, 40%);">+8060944c6256042c00010102f03c6cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0</span><br><span style="color: hsl(120, 100%, 40%);">+tx_msg() invoked by iuup_cn!</span><br><span style="color: hsl(120, 100%, 40%);">+ <-PDU- [IuUP]</span><br><span style="color: hsl(120, 100%, 40%);">+8060944c6256042c0001010203009eb36cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0</span><br><span style="color: hsl(120, 100%, 40%);">+node_priv=0x2342</span><br><span style="color: hsl(120, 100%, 40%);">+ok: matches expected msg</span><br><span style="color: hsl(120, 100%, 40%);">+rc=0</span><br><span style="color: hsl(120, 100%, 40%);">+All done.</span><br><span>diff --git a/tests/mgcp/mgcp_test.c b/tests/mgcp/mgcp_test.c</span><br><span>index 8a37ef0..5074de5 100644</span><br><span>--- a/tests/mgcp/mgcp_test.c</span><br><span>+++ b/tests/mgcp/mgcp_test.c</span><br><span>@@ -28,6 +28,7 @@</span><br><span> #include <osmocom/mgcp/mgcp_endp.h></span><br><span> #include <osmocom/mgcp/mgcp_sdp.h></span><br><span> #include <osmocom/mgcp/mgcp_codec.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mgcp/mgcp_internal.h></span><br><span> </span><br><span> #include <osmocom/core/application.h></span><br><span> #include <osmocom/core/talloc.h></span><br><span>@@ -1237,7 +1238,7 @@</span><br><span> void mgcp_patch_and_count(struct mgcp_endpoint *endp,</span><br><span>                         struct mgcp_rtp_state *state,</span><br><span>                        struct mgcp_rtp_end *rtp_end,</span><br><span style="color: hsl(0, 100%, 40%);">-                   struct sockaddr_in *addr, char *data, int len);</span><br><span style="color: hsl(120, 100%, 40%);">+                       struct sockaddr_in *addr, struct msgb *msg);</span><br><span> </span><br><span> static void test_packet_error_detection(int patch_ssrc, int patch_ts)</span><br><span> {</span><br><span>@@ -1249,7 +1250,6 @@</span><br><span>     struct mgcp_rtp_state state;</span><br><span>         struct mgcp_rtp_end *rtp;</span><br><span>    struct sockaddr_in addr = { 0 };</span><br><span style="color: hsl(0, 100%, 40%);">-        char buffer[4096];</span><br><span>   uint32_t last_ssrc = 0;</span><br><span>      uint32_t last_timestamp = 0;</span><br><span>         uint32_t last_seqno = 0;</span><br><span>@@ -1297,16 +1297,17 @@</span><br><span> </span><br><span>       for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) {</span><br><span>             struct rtp_packet_info *info = test_rtp_packets1 + i;</span><br><span style="color: hsl(120, 100%, 40%);">+         struct msgb *msg = msgb_alloc(4096, __func__);</span><br><span> </span><br><span>           force_monotonic_time_us = round(1000000.0 * info->txtime);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-               OSMO_ASSERT(info->len <= sizeof(buffer));</span><br><span style="color: hsl(120, 100%, 40%);">+               OSMO_ASSERT(info->len <= msgb_tailroom(msg));</span><br><span>          OSMO_ASSERT(info->len >= 0);</span><br><span style="color: hsl(0, 100%, 40%);">-              memmove(buffer, info->data, info->len);</span><br><span style="color: hsl(120, 100%, 40%);">+         msg->l3h = msgb_put(msg, info->len);</span><br><span style="color: hsl(120, 100%, 40%);">+            memcpy((char*)msgb_l3(msg), info->data, info->len);</span><br><span>            mgcp_rtp_end_config(&endp, 1, rtp);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-             mgcp_patch_and_count(&endp, &state, rtp, &addr,</span><br><span style="color: hsl(0, 100%, 40%);">-                                  buffer, info->len);</span><br><span style="color: hsl(120, 100%, 40%);">+           mgcp_patch_and_count(&endp, &state, rtp, &addr, msg);</span><br><span> </span><br><span>                if (state.out_stream.ssrc != last_ssrc) {</span><br><span>                    printf("Output SSRC changed to %08x\n",</span><br><span>@@ -1333,6 +1334,8 @@</span><br><span>            last_out_ts_err_cnt = state.out_stream.err_ts_ctr->current;</span><br><span>               last_timestamp = state.out_stream.last_timestamp;</span><br><span>            last_seqno = state.out_stream.last_seq;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             msgb_free(msg);</span><br><span>      }</span><br><span> </span><br><span>        force_monotonic_time_us = -1;</span><br><span>diff --git a/tests/testsuite.at b/tests/testsuite.at</span><br><span>index 3585bf0..0c3f802 100644</span><br><span>--- a/tests/testsuite.at</span><br><span>+++ b/tests/testsuite.at</span><br><span>@@ -13,3 +13,10 @@</span><br><span> cat $abs_srcdir/mgcp/mgcp_test.ok > expout</span><br><span> AT_CHECK([$abs_top_builddir/tests/mgcp/mgcp_test], [], [expout], [ignore])</span><br><span> AT_CLEANUP</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+AT_SETUP([iuup])</span><br><span style="color: hsl(120, 100%, 40%);">+AT_KEYWORDS([iuup])</span><br><span style="color: hsl(120, 100%, 40%);">+cat $abs_srcdir/iuup/iuup_test.ok > expout</span><br><span style="color: hsl(120, 100%, 40%);">+cat $abs_srcdir/iuup/iuup_test.err > experr</span><br><span style="color: hsl(120, 100%, 40%);">+AT_CHECK([$abs_top_builddir/tests/iuup/iuup_test], [], [expout], [experr])</span><br><span style="color: hsl(120, 100%, 40%);">+AT_CLEANUP</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-mgw/+/15169">change 15169</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/+/15169"/><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: Ibc70e0aa00476926dd1f4ea8139c34f31f9cdfa3 </div>
<div style="display:none"> Gerrit-Change-Number: 15169 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: neels <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>