add simplistic IuUP FSM and strip/add IuUP headers
This should really be using the FSM in libosmocore/laforge/iu_up: take the best
of both sides and integate in the libosmocore FSM implementation, then use it
here.
- in libosmocore, the FSM definition is nicer.
- here, we have correct header checksums.
This patch here also adds RTP header stripping/adding functionality, after
introducing using msgb to pass data around.
Change-Id: Ibc70e0aa00476926dd1f4ea8139c34f31f9cdfa3
diff --git a/include/osmocom/mgcp/debug.h b/include/osmocom/mgcp/debug.h
index ddeb0dc..1eed769 100644
--- a/include/osmocom/mgcp/debug.h
+++ b/include/osmocom/mgcp/debug.h
@@ -29,6 +29,7 @@
/* Debug Areas of the code */
enum {
DRTP,
+ DIUUP,
Debug_LastEntry,
};
diff --git a/include/osmocom/mgcp/iuup_cn_node.h b/include/osmocom/mgcp/iuup_cn_node.h
new file mode 100644
index 0000000..f792469
--- /dev/null
+++ b/include/osmocom/mgcp/iuup_cn_node.h
@@ -0,0 +1,41 @@
+/* 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);
+
+struct osmo_iuup_cn_cfg {
+ void *node_priv;
+
+ /* When the IuUP peer sent a voice packet, the clean RTP without the IuUP header is fed to this
+ * callback. */
+ osmo_iuup_data_cb_t rx_payload;
+
+ /* IuUP handler requests that a PDU shall be sent to the IuUP peer (e.g. the RNC).
+ * It is guaranteed that the msgb->dst pointer is preserved or copied from the msgb that
+ * originated the request. */
+ 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);
+
+int osmo_iuup_cn_tx_payload(struct osmo_iuup_cn *cn, struct msgb *payload);
+
+int osmo_iuup_cn_rx_pdu(struct osmo_iuup_cn *cn, struct msgb *pdu);
diff --git a/include/osmocom/mgcp/iuup_protocol.h b/include/osmocom/mgcp/iuup_protocol.h
new file mode 100644
index 0000000..f4aec1f
--- /dev/null
+++ b/include/osmocom/mgcp/iuup_protocol.h
@@ -0,0 +1,117 @@
+/* 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,
+ OSMO_IUUP_PROC_RATE_CONTROL = 1,
+ OSMO_IUUP_PROC_TIME_ALIGNMENT = 2,
+ OSMO_IUUP_PROC_ERROR_EVENT = 3,
+};
+
+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];
+#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];
+#endif
+} __attribute__((packed));
+
+union osmo_iuup_hdr_ctrl_payload {
+ struct {
+#if OSMO_IS_BIG_ENDIAN
+ uint8_t spare:3,
+ iptis_present:1,
+ subflows:3,
+ chain:1;
+#elif OSMO_IS_LITTLE_ENDIAN
+ uint8_t spare:3,
+ iptis_present:1,
+ subflows:3,
+ chain:1;
+#endif
+ } initialization;
+
+ struct {
+#if OSMO_IS_BIG_ENDIAN
+ uint8_t error_distance:2,
+ error_cause:6;
+#elif OSMO_IS_LITTLE_ENDIAN
+ uint8_t error_cause:6,
+ error_distance:2;
+#endif
+ } error_event;
+};
+
+extern const struct value_string osmo_iuup_error_cause_names[];
+static inline const char *osmo_iuup_error_cause_name(uint8_t val)
+{ return get_value_string(osmo_iuup_error_cause_names, val); }
+
+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..04c3d18 100644
--- a/include/osmocom/mgcp/mgcp_endp.h
+++ b/include/osmocom/mgcp/mgcp_endp.h
@@ -23,15 +23,28 @@
#pragma once
+#include <osmocom/core/msgb.h>
+
struct sockaddr_in;
struct mgcp_conn;
+struct mgcp_conn_rtp;
struct mgcp_endpoint;
-/* 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 mgcp_conn *conn);
+struct osmo_rtp_msg_ctx {
+ int proto;
+ struct mgcp_conn_rtp *conn_src;
+ struct sockaddr_in *from_addr;
+};
+
+#define OSMO_RTP_MSG_CTX(MSGB) (*(struct osmo_rtp_msg_ctx**)&((MSGB)->dst))
+
+#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).
+ * The fields OSMO_RTP_MSG_PROTO, OSMO_RTP_MSG_CONN_SRC, OSMO_RTP_MSG_FROM_ADDR should be set
+ * appropriately on the msg. */
+typedef int (*mgcp_dispatch_rtp_cb) (struct msgb *msg);
/* Callback type for endpoint specific cleanup actions. This function
* is automatically executed when a connection is freed (see mgcp_conn_free()
diff --git a/include/osmocom/mgcp/mgcp_internal.h b/include/osmocom/mgcp/mgcp_internal.h
index f75ae8b..51d3b9d 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,10 @@
};
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(struct msgb *msg);
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 +336,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);