wip

Change-Id: Ibc70e0aa00476926dd1f4ea8139c34f31f9cdfa3
diff --git a/include/osmocom/mgcp/iuup_cn_node.h b/include/osmocom/mgcp/iuup_cn_node.h
new file mode 100644
index 0000000..158b6a1
--- /dev/null
+++ b/include/osmocom/mgcp/iuup_cn_node.h
@@ -0,0 +1,46 @@
+/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
+/* IuUP CN node, minimal implementation */
+
+/*                                            _____IuUP_CN_____
+ *                                            |               |
+ * UE <--> RNC --PDU-> osmo_iuup_cn_rx_pdu() -+->           ---+-> rx_payload()
+ *          |                                 |               |
+ *          |  <-PDU-- tx_msg() <-------------+--           <-+--- osmo_iuup_cn_tx_payload()
+ *                                            |               |
+ *                                            -----------------
+ */
+
+
+#pragma once
+
+struct osmo_iuup_cn;
+struct msgb;
+
+typedef int (*osmo_iuup_data_cb_t)(struct msgb *msg, void *node_priv, void *pdu_priv);
+
+struct osmo_iuup_cn_cfg {
+	void *node_priv;
+
+	/* When an IuUP PDU containing voice payload has been received, this callback is invoked to pass
+	 * the voice payload towards the Core Network, msgb_l3() pointing at the payload. */
+	osmo_iuup_data_cb_t rx_payload;
+
+	/* IuUP handler sends a PDU to the IuUP peer (e.g. the RNC) */
+	osmo_iuup_data_cb_t tx_msg;
+};
+
+bool osmo_iuup_cn_is_iuup_init(struct msgb *msg);
+
+struct osmo_iuup_cn *osmo_iuup_cn_init(void *ctx, struct osmo_iuup_cn_cfg *cfg,
+				       const char *name_fmt, ...);
+void osmo_iuup_cn_free(struct osmo_iuup_cn *cn);
+
+/* Encapsulate voice stream payload in IuUP and, if appropriate, call the tx_msg() to transmit the
+ * resulting message to the IuUP peer. msgb_l3() should point at the payload data.
+ * pdu_priv is transparently passed on to tx_msg().
+ * Returns 0 on success, negative on error. */
+int osmo_iuup_cn_tx_payload(struct osmo_iuup_cn *cn, struct msgb *payload, void *pdu_priv);
+
+/* Feed a received PDU to the IuUP CN node. This function takes ownership of the msgb, it must not be
+ * freed by the caller. */
+int osmo_iuup_cn_rx_pdu(struct osmo_iuup_cn *cn, struct msgb *pdu, void *pdu_priv);
diff --git a/include/osmocom/mgcp/iuup_protocol.h b/include/osmocom/mgcp/iuup_protocol.h
new file mode 100644
index 0000000..108bcaa
--- /dev/null
+++ b/include/osmocom/mgcp/iuup_protocol.h
@@ -0,0 +1,92 @@
+/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
+/* IuUP protocol handling, minimal implementation */
+
+#pragma once
+
+#include <osmocom/core/endian.h>
+#include <osmocom/core/msgb.h>
+
+#define OSMO_IUUP_HEADROOM 32
+
+enum osmo_iuup_pdu_type {
+	OSMO_IUUP_PDU_DATA_WITH_CRC = 0,
+	OSMO_IUUP_PDU_CONTROL_PROCEDURE = 14,
+};
+
+enum osmo_iuup_acknack {
+	OSMO_IUUP_ACKNACK_PROCEDURE = 0,
+	OSMO_IUUP_ACKNACK_ACK = 1,
+	OSMO_IUUP_ACKNACK_NACK = 2,
+};
+
+enum osmo_iuup_procedure {
+	OSMO_IUUP_PROC_INITIALIZATION = 0,
+};
+
+enum osmo_iuup_frame_good {
+	OSMO_IUUP_FRAME_GOOD = 0,
+	OSMO_IUUP_FRAME_BAD = 1,
+	OSMO_IUUP_FRAME_BAD_DUE_TO_RADIO = 2,
+};
+
+struct osmo_iuup_hdr_ctrl {
+#if OSMO_IS_BIG_ENDIAN
+	uint8_t pdu_type:4,
+		ack_nack:2,
+		frame_nr:2;
+	uint8_t mode_version:4,
+		procedure:4;
+	uint8_t header_crc:6,
+		payload_crc_hi:2;
+	uint8_t payload_crc_lo;
+	uint8_t payload[0];
+	uint8_t spare:3,
+		iptis_present:1,
+		subflows:3,
+		chain:1;
+#elif OSMO_IS_LITTLE_ENDIAN
+	uint8_t frame_nr:2,
+		ack_nack:2,
+		pdu_type:4;
+	uint8_t procedure:4,
+		mode_version:4;
+	uint8_t payload_crc_hi:2,
+		header_crc:6;
+	uint8_t payload_crc_lo;
+	uint8_t payload[0];
+	uint8_t spare:3,
+		iptis_present:1,
+		subflows:3,
+		chain:1;
+#endif
+} __attribute__((packed));
+
+struct osmo_iuup_hdr_data {
+#if OSMO_IS_BIG_ENDIAN
+	uint8_t pdu_type:4,
+		frame_nr:4;
+	uint8_t frame_good:2,
+		rfci:6;
+	uint8_t header_crc:6,
+		payload_crc_hi:2;
+	uint8_t payload_crc_lo;
+#elif OSMO_IS_LITTLE_ENDIAN
+	uint8_t frame_nr:4,
+		pdu_type:4;
+	uint8_t rfci:6,
+		frame_good:2;
+	uint8_t payload_crc_hi:2,
+		header_crc:6;
+	uint8_t payload_crc_lo;
+#endif
+	uint8_t payload[0];
+} __attribute__((packed));
+
+int osmo_iuup_classify(bool log_errors,
+		       const char *log_label,
+		       struct msgb *pdu,
+		       struct osmo_iuup_hdr_ctrl **is_ctrl,
+		       struct osmo_iuup_hdr_data **is_data);
+bool osmo_iuup_is_init(struct msgb *pdu);
+void osmo_iuup_make_init_ack(struct msgb *ack);
+void osmo_iuup_set_checksums(uint8_t *iuup_header_and_payload, unsigned int header_and_payload_len);
diff --git a/include/osmocom/mgcp/mgcp_endp.h b/include/osmocom/mgcp/mgcp_endp.h
index a23e192..469d431 100644
--- a/include/osmocom/mgcp/mgcp_endp.h
+++ b/include/osmocom/mgcp/mgcp_endp.h
@@ -27,10 +27,13 @@
 struct mgcp_conn;
 struct mgcp_endpoint;
 
+#define LOG_ENDP(endp, level, fmt, args...) \
+	LOGP(DRTP, level, "%x@ " fmt, ENDPOINT_NUMBER(endp), ## args)
+
 /* Callback type for RTP dispatcher functions
    (e.g mgcp_dispatch_rtp_bridge_cb, see below) */
 typedef int (*mgcp_dispatch_rtp_cb) (int proto, struct sockaddr_in *addr,
-				     char *buf, unsigned int buf_size,
+				     struct msgb *payload,
 				     struct mgcp_conn *conn);
 
 /* Callback type for endpoint specific cleanup actions. This function
diff --git a/include/osmocom/mgcp/mgcp_internal.h b/include/osmocom/mgcp/mgcp_internal.h
index f75ae8b..69ba4d4 100644
--- a/include/osmocom/mgcp/mgcp_internal.h
+++ b/include/osmocom/mgcp/mgcp_internal.h
@@ -37,6 +37,13 @@
 #define CONN_ID_BTS "0"
 #define CONN_ID_NET "1"
 
+#define LOG_CONN(conn, level, fmt, args...) \
+	LOGP(DRTP, level, "(%d@ I:%s) " fmt, \
+	     ENDPOINT_NUMBER((conn)->endp), (conn)->id, ## args)
+
+#define LOG_CONN_RTP(conn_rtp, level, fmt, args...) \
+	LOG_CONN(conn_rtp->conn, level, fmt, ## args)
+
 enum mgcp_trunk_type {
 	MGCP_TRUNK_VIRTUAL,
 	MGCP_TRUNK_E1,
@@ -200,6 +207,8 @@
 	} osmux;
 
 	struct rate_ctr_group *rate_ctr_group;
+
+	struct osmo_iuup_cn *iuup;
 };
 
 /*! Connection type, specifies which member of the union "u" in mgcp_conn
@@ -259,11 +268,11 @@
 };
 
 int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
-	      char *buf, int rc, struct mgcp_conn_rtp *conn_src,
+	      struct msgb *msg, struct mgcp_conn_rtp *conn_src,
 	      struct mgcp_conn_rtp *conn_dst);
 int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn);
-int mgcp_dispatch_rtp_bridge_cb(int proto, struct sockaddr_in *addr, char *buf,
-				unsigned int buf_size, struct mgcp_conn *conn);
+int mgcp_dispatch_rtp_bridge_cb(int proto, struct sockaddr_in *addr,
+				struct msgb *payload, struct mgcp_conn *conn);
 void mgcp_cleanup_rtp_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
 int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
 			   struct mgcp_conn_rtp *conn);
@@ -328,3 +337,8 @@
 #define PTYPE_UNDEFINED (-1)
 
 void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn);
+
+void mgcp_patch_and_count(struct mgcp_endpoint *endp,
+			  struct mgcp_rtp_state *state,
+			  struct mgcp_rtp_end *rtp_end,
+			  struct sockaddr_in *addr, struct msgb *msg);