wip
Change-Id: I4fdcebf3b006a72c5318a9105a2be2cc7057dca1
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
index 158b6a1..f792469 100644
--- a/include/osmocom/mgcp/iuup_cn_node.h
+++ b/include/osmocom/mgcp/iuup_cn_node.h
@@ -10,22 +10,23 @@
* -----------------
*/
-
#pragma once
struct osmo_iuup_cn;
struct msgb;
-typedef int (*osmo_iuup_data_cb_t)(struct msgb *msg, void *node_priv, void *pdu_priv);
+typedef int (*osmo_iuup_data_cb_t)(struct msgb *msg, void *node_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. */
+ /* 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 sends a PDU to the IuUP peer (e.g. the RNC) */
+ /* 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;
};
@@ -35,12 +36,6 @@
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);
+int osmo_iuup_cn_tx_payload(struct osmo_iuup_cn *cn, struct msgb *payload);
-/* 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);
+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
index 108bcaa..f4aec1f 100644
--- a/include/osmocom/mgcp/iuup_protocol.h
+++ b/include/osmocom/mgcp/iuup_protocol.h
@@ -21,6 +21,9 @@
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 {
@@ -40,10 +43,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,
@@ -54,12 +53,38 @@
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
-} __attribute__((packed));
+ } 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
diff --git a/include/osmocom/mgcp/mgcp_endp.h b/include/osmocom/mgcp/mgcp_endp.h
index 469d431..04c3d18 100644
--- a/include/osmocom/mgcp/mgcp_endp.h
+++ b/include/osmocom/mgcp/mgcp_endp.h
@@ -23,18 +23,28 @@
#pragma once
+#include <osmocom/core/msgb.h>
+
struct sockaddr_in;
struct mgcp_conn;
+struct mgcp_conn_rtp;
struct mgcp_endpoint;
+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) */
-typedef int (*mgcp_dispatch_rtp_cb) (int proto, struct sockaddr_in *addr,
- struct msgb *payload,
- struct mgcp_conn *conn);
+/* 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 69ba4d4..51d3b9d 100644
--- a/include/osmocom/mgcp/mgcp_internal.h
+++ b/include/osmocom/mgcp/mgcp_internal.h
@@ -271,8 +271,7 @@
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,
- struct msgb *payload, 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);
diff --git a/src/libosmo-mgcp/iuup_cn_node.c b/src/libosmo-mgcp/iuup_cn_node.c
index 390dc1c..f555e36 100644
--- a/src/libosmo-mgcp/iuup_cn_node.c
+++ b/src/libosmo-mgcp/iuup_cn_node.c
@@ -39,12 +39,13 @@
#include <osmocom/mgcp/debug.h>
#define LOG_IUUP_CN(cn, level, fmt, args...) \
- LOGP(DRTP, level, "(%s) " fmt, (cn)->name, ## args)
+ LOGP(DIUUP, level, "(%s) " fmt, (cn)->name, ## args)
struct osmo_iuup_cn {
struct osmo_iuup_cn_cfg cfg;
char *name;
uint8_t next_frame_nr;
+ int rtp_payload_type;
};
struct osmo_iuup_cn *osmo_iuup_cn_init(void *ctx, struct osmo_iuup_cn_cfg *cfg,
@@ -63,8 +64,10 @@
cn->name = talloc_vasprintf(cn, name_fmt, ap);
va_end(ap);
+ LOGP(DIUUP, LOGL_INFO, "(%s) Initializing IuUP node\n", cn->name);
+
if (!osmo_identifier_valid(cn->name)) {
- LOGP(DLGLOBAL, LOGL_ERROR, "Attempting to set illegal id for IuUP CN instance: %s\n",
+ LOGP(DIUUP, LOGL_ERROR, "Attempting to set illegal id for IuUP CN instance: %s\n",
osmo_quote_str(cn->name, -1));
talloc_free(cn);
return NULL;
@@ -79,7 +82,7 @@
}
static int rx_data(struct osmo_iuup_cn *cn, struct msgb *pdu,
- struct osmo_iuup_hdr_data *hdr, void *pdu_priv)
+ struct osmo_iuup_hdr_data *hdr)
{
/* Remove the IuUP bit from the middle of the buffer by writing the RTP header forward. */
unsigned int pre_hdr_len = ((uint8_t*)hdr) - pdu->data;
@@ -87,42 +90,72 @@
msgb_pull(pdu, sizeof(*hdr));
- cn->cfg.rx_payload(pdu, cn->cfg.node_priv, pdu_priv);
+ LOGP(DIUUP, LOGL_DEBUG, "(%s) IuUP stripping IuUP header from RTP data\n", cn->name);
+ cn->cfg.rx_payload(pdu, cn->cfg.node_priv);
return 0;
}
-static int tx_init_ack(struct osmo_iuup_cn *cn, void *pdu_priv)
+static int tx_init_ack(struct osmo_iuup_cn *cn, struct msgb *src_pdu)
{
/* Send Initialization Ack PDU back to the sender */
+ int rc;
struct msgb *ack = msgb_alloc(4096, "IuUP Initialization Ack");
OSMO_ASSERT(ack);
+ ack->dst = src_pdu->dst;
+
+ /* Just copy the RTP header that was sent... TODO: tweak some RTP values?? */
+ memcpy(msgb_put(ack, sizeof(struct rtp_hdr)), src_pdu->data, sizeof(struct rtp_hdr));
+
osmo_iuup_make_init_ack(ack);
- return cn->cfg.tx_msg(ack, cn->cfg.node_priv, pdu_priv);
+
+ LOGP(DIUUP, LOGL_DEBUG, "(%s) Sending Initialization ACK %p\n", cn->name, cn->cfg.node_priv);
+ rc = cn->cfg.tx_msg(ack, cn->cfg.node_priv);
+ msgb_free(ack);
+ return rc;
}
static int rx_control(struct osmo_iuup_cn *cn, struct msgb *pdu,
- struct osmo_iuup_hdr_ctrl *hdr, void *pdu_priv)
+ struct osmo_iuup_hdr_ctrl *hdr)
{
switch (hdr->procedure) {
case OSMO_IUUP_PROC_INITIALIZATION:
switch (hdr->ack_nack) {
case OSMO_IUUP_ACKNACK_PROCEDURE:
- return tx_init_ack(cn, pdu_priv);
+ LOGP(DIUUP, LOGL_INFO, "(%s) Rx IuUP Initialization, sending ACK\n", cn->name);
+ cn->rtp_payload_type = ((struct rtp_hdr*)pdu->data)->payload_type;
+ return tx_init_ack(cn, pdu);
default:
+ LOGP(DIUUP, LOGL_DEBUG, "(%s) Rx IuUP Initialization, unhandled ack_nack = %d\n",
+ cn->name, hdr->ack_nack);
break;
}
- /* fall thru */
+ /* Continue to log "unexpected procedure" below. */
+ break;
+
+ case OSMO_IUUP_PROC_ERROR_EVENT:
+ {
+ union osmo_iuup_hdr_ctrl_payload *p = (void*)hdr->payload;
+ LOGP(DIUUP, LOGL_ERROR,
+ "(%s) Rx IuUP Error Event: distance=%u, cause=%u=\"%s\"\n",
+ cn->name, p->error_event.error_distance, p->error_event.error_cause,
+ osmo_iuup_error_cause_name(p->error_event.error_cause));
+ return 0;
+ }
+
default:
- LOG_IUUP_CN(cn, LOGL_ERROR,
- "Rx control PDU with unexpected procedure: 0x%x acknack=0x%x\n",
- hdr->procedure, hdr->ack_nack);
- return -EINVAL;
+ break;
}
+ LOG_IUUP_CN(cn, LOGL_ERROR,
+ "Rx control PDU with unexpected procedure: 0x%x acknack=0x%x\n",
+ hdr->procedure, hdr->ack_nack);
+ return -EINVAL;
}
-int osmo_iuup_cn_rx_pdu(struct osmo_iuup_cn *cn, struct msgb *pdu, 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)
{
struct osmo_iuup_hdr_ctrl *is_ctrl;
struct osmo_iuup_hdr_data *is_data;
@@ -133,20 +166,23 @@
return rc;
if (is_ctrl)
- return rx_control(cn, pdu, is_ctrl, pdu_priv);
+ return rx_control(cn, pdu, is_ctrl);
if (is_data)
- return rx_data(cn, pdu, is_data, pdu_priv);
+ return rx_data(cn, pdu, is_data);
return rc;
}
static uint8_t next_frame_nr(struct osmo_iuup_cn *cn)
{
uint8_t frame_nr = cn->next_frame_nr;
- cn->next_frame_nr = (cn->next_frame_nr + 1) % 0x0f;
+ cn->next_frame_nr = (frame_nr + 1) & 0x0f;
return frame_nr;
}
-int osmo_iuup_cn_tx_payload(struct osmo_iuup_cn *cn, struct msgb *pdu, void *pdu_priv)
+/* Send this RTP packet to the IuUP peer: add IuUP header and call the tx_msg() to transmit the resulting
+ * message to the IuUP peer.
+ * Returns 0 on success, negative on error. */
+int osmo_iuup_cn_tx_payload(struct osmo_iuup_cn *cn, struct msgb *pdu)
{
struct rtp_hdr *rtp_was, *rtp;
struct osmo_iuup_hdr_data *iuup_hdr;
@@ -157,6 +193,10 @@
/* copy the RTP header part backwards by the size needed for the IuUP header */
rtp = (void*)msgb_push(pdu, sizeof(*iuup_hdr));
memmove(rtp, rtp_was, sizeof(*rtp));
+
+ /* Send the same payload type to the peer (erm...) */
+ rtp->payload_type = cn->rtp_payload_type;
+
iuup_hdr = (void*)rtp->data;
*iuup_hdr = (struct osmo_iuup_hdr_data){
@@ -166,6 +206,8 @@
};
osmo_iuup_set_checksums((uint8_t*)iuup_hdr, pdu->tail - (uint8_t*)iuup_hdr);
+ LOGP(DIUUP, LOGL_DEBUG, "(%s) IuUP inserting IuUP header in RTP data (frame nr %u)\n",
+ cn->name, iuup_hdr->frame_nr);
- return cn->cfg.tx_msg(pdu, cn->cfg.node_priv, pdu_priv);
+ return cn->cfg.tx_msg(pdu, cn->cfg.node_priv);
}
diff --git a/src/libosmo-mgcp/iuup_protocol.c b/src/libosmo-mgcp/iuup_protocol.c
index 6277abd..bfb009d 100644
--- a/src/libosmo-mgcp/iuup_protocol.c
+++ b/src/libosmo-mgcp/iuup_protocol.c
@@ -152,7 +152,7 @@
/* Validate minimum message sizes, IuUP PDU type, header- and payload checksums. If it is a Control
* Procedure PDU, return the header position in is_ctrl, if it is a Data PDU, return the header position
- * in is_data. If log_errors is true, log on DRTP with the given log label for context. Return NULL in
+ * in is_data. If log_errors is true, log on DIUUP with the given log label for context. Return NULL in
* both is_ctrl and is_data, and return a negative error code if the PDU could not be identified as a
* valid RTP PDU containing an IuUP part. */
int osmo_iuup_classify(bool log_errors,
@@ -169,7 +169,7 @@
#define ERR(fmt, args...) do { \
if (log_errors) \
- LOGP(DRTP, LOGL_ERROR, "(%s) " fmt, log_label? : "-", ## args); \
+ LOGP(DIUUP, LOGL_ERROR, "(%s) " fmt, log_label? : "-", ## args); \
return -EINVAL; \
} while (0)
@@ -240,6 +240,7 @@
&& is_ctrl->ack_nack == OSMO_IUUP_ACKNACK_PROCEDURE;
}
+/* Append an IuUP Initialization ACK message */
void osmo_iuup_make_init_ack(struct msgb *ack)
{
/* Send Initialization Ack PDU back to the sender */
@@ -256,3 +257,30 @@
osmo_iuup_set_checksums((uint8_t*)hdr, sizeof(*hdr));
}
+
+const struct value_string osmo_iuup_error_cause_names[] = {
+ { 0, "CRC error of frame header" },
+ { 1, "CRC error of frame payload" },
+ { 2, "Unexpected frame number" },
+ { 3, "Frame loss" },
+ { 4, "PDU type unknown" },
+ { 5, "Unknown procedure" },
+ { 6, "Unknown reserved value" },
+ { 7, "Unknown field" },
+ { 8, "Frame too short" },
+ { 9, "Missing fields" },
+ { 16, "Unexpected PDU type" },
+ { 17, "spare" },
+ { 18, "Unexpected procedure" },
+ { 19, "Unexpected RFCI" },
+ { 20, "Unexpected value" },
+ { 42, "Initialisation failure" },
+ { 43, "Initialisation failure (network error, timer expiry)" },
+ { 44, "Initialisation failure (Iu UP function error, repeated NACK)" },
+ { 45, "Rate control failure" },
+ { 46, "Error event failure" },
+ { 47, "Time Alignment not supported" },
+ { 48, "Requested Time Alignment not possible" },
+ { 49, "Iu UP Mode version not supported" },
+ {}
+};
diff --git a/src/libosmo-mgcp/mgcp_network.c b/src/libosmo-mgcp/mgcp_network.c
index e4ee8ad..83c0570 100644
--- a/src/libosmo-mgcp/mgcp_network.c
+++ b/src/libosmo-mgcp/mgcp_network.c
@@ -57,10 +57,7 @@
MGCP_PROTO_RTCP,
};
-static int rx_rtp(struct mgcp_conn_rtp *conn_src, struct msgb *payload,
- enum rtp_proto proto, struct sockaddr_in *from_addr);
-static int tx_rtp(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst,
- enum rtp_proto proto, struct sockaddr_in *from_addr, struct msgb *payload);
+static int rx_rtp(struct msgb *msg);
/*! Determine the local rtp bind IP-address.
* \param[out] addr caller provided memory to store the resulting IP-Address
@@ -494,8 +491,8 @@
uint8_t pt_in;
int pt_out;
- OSMO_ASSERT(msgb_l3len(msg) >= sizeof(struct rtp_hdr));
- rtp_hdr = (struct rtp_hdr *)msgb_l3(msg);
+ OSMO_ASSERT(msg->len >= sizeof(struct rtp_hdr));
+ rtp_hdr = (struct rtp_hdr *)msg->data;
pt_in = rtp_hdr->payload_type;
pt_out = mgcp_codec_pt_translate(conn_src, conn_dst, pt_in);
@@ -523,12 +520,12 @@
uint32_t timestamp, ssrc;
struct rtp_hdr *rtp_hdr;
int payload = rtp_end->codec->payload_type;
- unsigned int len = msgb_l3len(msg);
+ unsigned int len = msg->len;
if (len < sizeof(*rtp_hdr))
return;
- rtp_hdr = (struct rtp_hdr *)msgb_l3(msg);
+ rtp_hdr = (struct rtp_hdr *)msg->data;
seq = ntohs(rtp_hdr->sequence);
timestamp = ntohl(rtp_hdr->timestamp);
arrival_time = get_current_ts(rtp_end->codec->rate);
@@ -668,7 +665,7 @@
if (!tap->enabled)
return;
- rc = sendto(fd, msgb_l3(msg), msgb_l3len(msg), 0, (struct sockaddr *)&tap->forward,
+ rc = sendto(fd, msg->data, msg->len, 0, (struct sockaddr *)&tap->forward,
sizeof(tap->forward));
if (rc < 0)
@@ -754,11 +751,11 @@
} else if (is_rtp) {
int cont;
int nbytes = 0;
- int buflen = msgb_l3len(msg);
+ int buflen = msg->len;
do {
/* Run transcoder */
cont = endp->cfg->rtp_processing_cb(endp, rtp_end,
- msgb_l3(msg), &buflen,
+ (char*)msg->data, &buflen,
RTP_BUF_SIZE);
if (cont < 0)
break;
@@ -778,6 +775,7 @@
forward_data(rtp_end->rtp.fd, &conn_src->tap_out,
msg);
+#if 0
/* FIXME: HACK HACK HACK. See OS#2459.
* The ip.access nano3G needs the first RTP payload's first two bytes to read hex
* 'e400', or it will reject the RAB assignment. It seems to not harm other femto
@@ -785,7 +783,7 @@
*/
if (!rtp_state->patched_first_rtp_payload
&& conn_src->conn->mode == MGCP_CONN_LOOPBACK) {
- uint8_t *data = ((uint8_t *)msgb_l3(msg)) + 12;
+ uint8_t *data = msg->data + 12;
if (data[0] == 0xe0) {
data[0] = 0xe4;
data[1] = 0x00;
@@ -796,11 +794,13 @@
ENDPOINT_NUMBER(endp));
}
}
+#endif
- len = mgcp_udp_send(rtp_end->rtp.fd,
- &rtp_end->addr,
- rtp_end->rtp_port,
- msgb_l3(msg), msgb_l3len(msg));
+ if (conn_dst->iuup)
+ len = osmo_iuup_cn_tx_payload(conn_dst->iuup, msg);
+ else
+ len = mgcp_udp_send(rtp_end->rtp.fd, &rtp_end->addr, rtp_end->rtp_port,
+ (char*)msg->data, msg->len);
if (len <= 0)
return len;
@@ -823,7 +823,7 @@
len = mgcp_udp_send(rtp_end->rtcp.fd,
&rtp_end->addr,
- rtp_end->rtcp_port, msgb_l3(msg), msgb_l3len(msg));
+ rtp_end->rtcp_port, (char*)msg->data, msg->len);
rate_ctr_inc(&conn_dst->rate_ctr_group->ctr[RTP_PACKETS_TX_CTR]);
rate_ctr_add(&conn_dst->rate_ctr_group->ctr[RTP_OCTETS_TX_CTR], len);
@@ -914,7 +914,7 @@
* and IP-address for outgoing data. */
if (strcmp(inet_ntoa(conn->end.addr), "0.0.0.0") == 0 && conn->end.rtp_port == 0) {
LOGP(DRTP, LOGL_DEBUG,
- "endpoint:0x%x destination IP-address and rtp port is (not yet) known\n",
+ "endpoint:0x%x destination IP-address and rtp port is not known (yet)\n",
ENDPOINT_NUMBER(endp));
return -1;
}
@@ -943,23 +943,22 @@
struct rtcp_hdr *hdr;
unsigned int len;
uint8_t type;
- unsigned int buf_size = msgb_l3len(msg);
/* RTPC packets that are just a header without data do not make
* any sense. */
- if (buf_size < sizeof(struct rtcp_hdr)) {
+ if (msg->len < sizeof(struct rtcp_hdr)) {
LOG_CONN_RTP(conn_src, LOGL_ERROR, "RTCP packet too short (%u < %zu)\n",
- buf_size, sizeof(struct rtcp_hdr));
+ msg->len, sizeof(struct rtcp_hdr));
return -EINVAL;
}
/* Make sure that the length of the received packet does not exceed
* the available buffer size */
- hdr = (struct rtcp_hdr *)msgb_l3(msg);
+ hdr = (struct rtcp_hdr *)msg->data;
len = (osmo_ntohs(hdr->length) + 1) * 4;
- if (len > buf_size) {
+ if (len > msg->len) {
LOG_CONN_RTP(conn_src, LOGL_ERROR, "RTCP header length exceeds packet size (%u > %u)\n",
- len, buf_size);
+ len, msg->len);
return -EINVAL;
}
@@ -981,9 +980,9 @@
size_t min_size = sizeof(struct rtp_hdr);
if (conn_src->iuup)
min_size += sizeof(struct osmo_iuup_hdr_data);
- if (msgb_l3len(msg) < min_size) {
+ if (msg->len < min_size) {
LOG_CONN_RTP(conn_src, LOGL_ERROR, "RTP packet too short (%u < %zu)\n",
- msgb_l3len(msg), min_size);
+ msg->len, min_size);
return -1;
}
@@ -998,11 +997,11 @@
/* Send RTP data. Possible options are standard RTP packet
* transmission or trsmission via an osmux connection */
-static int mgcp_send_rtp(int proto, struct sockaddr_in *addr,
- struct msgb *payload,
- struct mgcp_conn_rtp *conn_src,
- struct mgcp_conn_rtp *conn_dst)
+static int mgcp_send_rtp(struct mgcp_conn_rtp *conn_dst, struct msgb *msg)
{
+ enum rtp_proto proto = OSMO_RTP_MSG_CTX(msg)->proto;
+ struct mgcp_conn_rtp *conn_src = OSMO_RTP_MSG_CTX(msg)->conn_src;
+ struct sockaddr_in *from_addr = OSMO_RTP_MSG_CTX(msg)->from_addr;
struct mgcp_endpoint *endp = conn_src->conn->endp;
LOGP(DRTP, LOGL_DEBUG, "endpoint:0x%x destin conn:%s\n",
@@ -1023,14 +1022,14 @@
"using mgcp_send() to forward data directly\n",
ENDPOINT_NUMBER(endp));
return mgcp_send(endp, proto == MGCP_PROTO_RTP,
- addr, payload, conn_src, conn_dst);
+ from_addr, msg, conn_src, conn_dst);
case MGCP_OSMUX_BSC_NAT:
case MGCP_OSMUX_BSC:
LOGP(DRTP, LOGL_DEBUG,
"endpoint:0x%x endpoint type is MGCP_OSMUX_BSC_NAT, "
"using osmux_xfrm_to_osmux() to forward data through OSMUX\n",
ENDPOINT_NUMBER(endp));
- return osmux_xfrm_to_osmux(msgb_l3(payload), msgb_l3len(payload), conn_dst);
+ return osmux_xfrm_to_osmux((char*)msg->data, msg->len, conn_dst);
}
/* If the data has not been handled/forwarded until here, it will
@@ -1050,9 +1049,10 @@
* \param[in] buf_size size data length of buf
* \param[in] conn originating connection
* \returns 0 on success, -1 on ERROR */
-int mgcp_dispatch_rtp_bridge_cb(int proto, struct sockaddr_in *addr,
- struct msgb *payload, struct mgcp_conn *conn)
+int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
{
+ struct mgcp_conn_rtp *conn_src = OSMO_RTP_MSG_CTX(msg)->conn_src;
+ struct mgcp_conn *conn = conn_src->conn;
struct mgcp_conn *conn_dst;
struct mgcp_endpoint *endp;
endp = conn->endp;
@@ -1096,7 +1096,7 @@
}
/* Dispatch RTP packet to destination RTP connection */
- return tx_rtp(&conn->u.rtp, &conn_dst->u.rtp, proto, addr, payload);
+ return mgcp_send_rtp(&conn_dst->u.rtp, msg);
}
/*! cleanup an endpoint when a connection on an RTP bridge endpoint is removed.
@@ -1120,14 +1120,7 @@
static bool is_dummy_msg(enum rtp_proto proto, struct msgb *msg)
{
- return msgb_l3len(msg) == 1 && ((char*)msgb_l3(msg))[0] == MGCP_DUMMY_LOAD;
-}
-
-int rx_rtp_from_iuup(struct msgb *msg, void *node_priv, void *pdu_priv)
-{
- struct mgcp_conn_rtp *conn_src = node_priv;
- struct sockaddr_in *from_addr = pdu_priv;
- return rx_rtp(conn_src, msg, MGCP_PROTO_RTP, from_addr);
+ return msg->len == 1 && msg->data[0] == MGCP_DUMMY_LOAD;
}
struct pdu_ctx {
@@ -1135,23 +1128,64 @@
struct mgcp_conn_rtp *conn_src;
};
-int tx_pdu_from_iuup(struct msgb *msg, void *node_priv, void *pdu_priv)
+/* IuUP CN node has stripped an IuUP header and forwards RTP data to distribute to the peers. */
+int iuup_rx_payload(struct msgb *msg, void *node_priv)
{
- struct mgcp_conn_rtp *conn_dst = node_priv;
- struct pdu_ctx *p = pdu_priv;
- return mgcp_send_rtp(MGCP_PROTO_RTP, p->from_addr, msg, p->conn_src, conn_dst);
+ struct mgcp_conn_rtp *conn_src = OSMO_RTP_MSG_CTX(msg)->conn_src;
+ LOG_CONN_RTP(conn_src, LOGL_DEBUG, "iuup_rx_payload(%u bytes)\n", msg->len);
+ return rx_rtp(msg);
}
-static void init_iuup(struct mgcp_conn_rtp *conn_src)
+/* IuUP CN node has composed a message that contains an IuUP header and asks us to send to the IuUP peer.
+ */
+int iuup_tx_msg(struct msgb *msg, void *node_priv)
+{
+ const struct in_addr zero_addr = {};
+ struct mgcp_conn_rtp *conn_src = OSMO_RTP_MSG_CTX(msg)->conn_src;
+ struct mgcp_conn_rtp *conn_dst = node_priv;
+ struct sockaddr_in *from_addr = OSMO_RTP_MSG_CTX(msg)->from_addr;
+ struct mgcp_rtp_end *rtp_end = &conn_dst->end;
+ struct in_addr to_addr = rtp_end->addr;
+ uint16_t to_port = rtp_end->rtp_port;
+
+ if (conn_src == conn_dst
+ && !memcmp(&zero_addr, &to_addr, sizeof(zero_addr)) && !to_port) {
+ LOG_CONN_RTP(conn_dst, LOGL_DEBUG, "iuup_tx_msg(): direct IuUP reply\n");
+ /* IuUP wants to send a message back to the same peer that sent an RTP package, but there
+ * is no address configured for that peer yet. It is probably an IuUP Initialization ACK
+ * reply. Use the sender address to send the reply.
+ *
+ * During 3G RAB Assignment, a 3G cell might first probe the MGW and expect an IuUP
+ * Initialization ACK before it replies to the MSC with a successful RAB Assignment; only
+ * after that reply does MSC officially know which RTP address+port the 3G cell wants to
+ * use and can tell this MGW about it, so this "loopback" is, for some 3G cells, the only
+ * chance we have to get a successful RAB Assignment done (particularly the nano3G does
+ * this). */
+ to_addr = from_addr->sin_addr;
+ to_port = from_addr->sin_port;
+ }
+
+ LOG_CONN_RTP(conn_dst, LOGL_DEBUG, "iuup_tx_msg(%u bytes) to %s:%u\n", msg->len,
+ inet_ntoa(to_addr), ntohs(to_port));
+
+ return mgcp_udp_send(rtp_end->rtp.fd, &to_addr, to_port, (char*)msg->data, msg->len);
+}
+
+static void iuup_init(struct mgcp_conn_rtp *conn_src)
{
struct osmo_iuup_cn_cfg cfg = {
.node_priv = conn_src,
- .rx_payload = rx_rtp_from_iuup,
- .tx_msg = tx_pdu_from_iuup,
+ .rx_payload = iuup_rx_payload,
+ .tx_msg = iuup_tx_msg,
};
- osmo_iuup_cn_init(conn_src, &cfg, "%d@ I:%s",
- ENDPOINT_NUMBER(conn_src->conn->endp), conn_src->conn->id);
+ if (conn_src->iuup) {
+ LOG_CONN_RTP(conn_src, LOGL_NOTICE, "Rx IuUP init, but already initialized. Ignoring.\n");
+ return;
+ }
+
+ conn_src->iuup = osmo_iuup_cn_init(conn_src->conn, &cfg, "endp_%d_conn_%s",
+ ENDPOINT_NUMBER(conn_src->conn->endp), conn_src->conn->id);
}
/* Handle incoming RTP data from NET */
@@ -1170,6 +1204,7 @@
socklen_t slen = sizeof(addr);
int ret;
enum rtp_proto proto;
+ struct osmo_rtp_msg_ctx mc;
struct msgb *msg = msgb_alloc_headroom(RTP_BUF_SIZE + OSMO_IUUP_HEADROOM,
OSMO_IUUP_HEADROOM, "RTP-rx");
@@ -1188,12 +1223,11 @@
return -1;
}
- /* By default, indicate that RTP payload starts right from the buffer's beginning. */
- msg->l3h = msgb_put(msg, ret);
+ msgb_put(msg, ret);
LOG_CONN_RTP(conn_src, LOGL_DEBUG, "%s: rx %u bytes from %s:%u\n",
proto == MGCP_PROTO_RTP ? "RTP" : "RTPC",
- msgb_l3len(msg), inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
+ msg->len, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
if ((proto == MGCP_PROTO_RTP && check_rtp(conn_src, msg))
|| (proto == MGCP_PROTO_RTCP && check_rtcp(conn_src, msg))) {
@@ -1206,32 +1240,47 @@
return 0;
}
+ mc = (struct osmo_rtp_msg_ctx){
+ .proto = proto,
+ .conn_src = conn_src,
+ .from_addr = &addr,
+ };
+ OSMO_RTP_MSG_CTX(msg) = &mc;
+ LOG_CONN_RTP(conn_src, LOGL_DEBUG, "msg ctx: %d %p %s\n",
+ OSMO_RTP_MSG_CTX(msg)->proto,
+ OSMO_RTP_MSG_CTX(msg)->conn_src,
+ osmo_hexdump((void*)OSMO_RTP_MSG_CTX(msg)->from_addr, sizeof(struct sockaddr_in)));
+
/* Increment RX statistics */
rate_ctr_inc(&conn_src->rate_ctr_group->ctr[RTP_PACKETS_RX_CTR]);
- rate_ctr_add(&conn_src->rate_ctr_group->ctr[RTP_OCTETS_RX_CTR], msgb_l3len(msg));
+ rate_ctr_add(&conn_src->rate_ctr_group->ctr[RTP_OCTETS_RX_CTR], msg->len);
/* FIXME: count RTP and RTCP separately, also count IuUP payload-less separately */
/* Forward a copy of the RTP data to a debug ip/port */
forward_data(fd->fd, &conn_src->tap_in, msg);
if (proto == MGCP_PROTO_RTP && osmo_iuup_is_init(msg))
- init_iuup(conn_src);
+ iuup_init(conn_src);
if (conn_src->iuup && proto == MGCP_PROTO_RTP)
- return osmo_iuup_cn_rx_pdu(conn_src->iuup, msg, &addr);
+ return osmo_iuup_cn_rx_pdu(conn_src->iuup, msg);
else
- return rx_rtp(conn_src, msg, proto, &addr);
+ return rx_rtp(msg);
+ msgb_free(msg);
}
-static int rx_rtp(struct mgcp_conn_rtp *conn_src, struct msgb *payload,
- enum rtp_proto proto, struct sockaddr_in *from_addr)
+static int rx_rtp(struct msgb *msg)
{
- struct mgcp_endpoint *endp = conn_src->conn->endp;
- struct mgcp_trunk_config *tcfg = endp->tcfg;
+ struct mgcp_conn_rtp *conn_src = OSMO_RTP_MSG_CTX(msg)->conn_src;
+ struct sockaddr_in *from_addr = OSMO_RTP_MSG_CTX(msg)->from_addr;
+ struct mgcp_conn *conn = conn_src->conn;
+ struct mgcp_trunk_config *tcfg = conn->endp->tcfg;
+
+ LOG_CONN_RTP(conn_src, LOGL_DEBUG, "rx_rtp(%u bytes)\n", msg->len);
/* Check if the connection is in loopback mode, if yes, just send the
* incoming data back to the origin */
- if (conn_src->conn->mode == MGCP_CONN_LOOPBACK) {
+ if (conn->mode == MGCP_CONN_LOOPBACK) {
/* When we are in loopback mode, we loop back all incoming
* packets back to their origin. We will use the originating
* address data from the UDP packet header to patch the
@@ -1240,7 +1289,7 @@
conn_src->end.addr = from_addr->sin_addr;
conn_src->end.rtp_port = from_addr->sin_port;
}
- return tx_rtp(conn_src, conn_src, proto, from_addr, payload);
+ return mgcp_send_rtp(conn_src, msg);
}
/* Check if the origin of the RTP packet seems plausible */
@@ -1249,16 +1298,7 @@
/* Execute endpoint specific implementation that handles the
* dispatching of the RTP data */
- return conn_src->conn->endp->type->dispatch_rtp_cb(proto, from_addr, payload, conn_src->conn);
-}
-
-static int tx_rtp(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst,
- enum rtp_proto proto, struct sockaddr_in *from_addr, struct msgb *payload)
-{
- if (conn_dst->iuup && proto == MGCP_PROTO_RTP)
- return osmo_iuup_cn_tx_payload(conn_dst->iuup, payload, from_addr);
- else
- return mgcp_send_rtp(proto, from_addr, payload, conn_src, conn_dst);
+ return conn->endp->type->dispatch_rtp_cb(msg);
}
/*! set IP Type of Service parameter.
diff --git a/src/osmo-mgw/mgw_main.c b/src/osmo-mgw/mgw_main.c
index de094c1..4abee75 100644
--- a/src/osmo-mgw/mgw_main.c
+++ b/src/osmo-mgw/mgw_main.c
@@ -244,6 +244,12 @@
.color = "\033[1;30m",
.enabled = 1,.loglevel = LOGL_NOTICE,
},
+ [DIUUP] = {
+ .name = "DIUUP",
+ .description = "IuUP within RTP stream handling",
+ .color = "\033[1;31m",
+ .enabled = 1,.loglevel = LOGL_NOTICE,
+ },
};
const struct log_info log_info = {
diff --git a/tests/iuup/iuup_test.c b/tests/iuup/iuup_test.c
index 8f32a95..8d96f06 100644
--- a/tests/iuup/iuup_test.c
+++ b/tests/iuup/iuup_test.c
@@ -27,12 +27,12 @@
}
const char *expect_rx_payload = NULL;
-int rx_payload(struct msgb *msg, void *node_priv, void *pdu_priv)
+int rx_payload(struct msgb *msg, void *node_priv)
{
printf("rx_payload() invoked by iuup_cn!\n");
printf(" [IuUP] -RTP->\n");
printf("%s\n", dump(msg));
- printf("node_priv=%p pdu_priv=%p\n", node_priv, pdu_priv);
+ printf("node_priv=%p\n", node_priv);
if (!expect_rx_payload) {
printf("ERROR: did not expect rx_payload()\n");
exit(-1);
@@ -41,18 +41,17 @@
exit(-1);
} else
printf("ok: matches expected msg\n");
- msgb_free(msg);
expect_rx_payload = NULL;
return 0;
}
const char *expect_tx_msg = NULL;
-int tx_msg(struct msgb *msg, void *node_priv, void *pdu_priv)
+int tx_msg(struct msgb *msg, void *node_priv)
{
printf("tx_msg() invoked by iuup_cn!\n");
printf(" <-PDU- [IuUP]\n");
printf("%s\n", dump(msg));
- printf("node_priv=%p pdu_priv=%p\n", node_priv, pdu_priv);
+ printf("node_priv=%p\n", node_priv);
if (!expect_tx_msg) {
printf("ERROR: did not expect tx_msg()\n");
exit(-1);
@@ -61,29 +60,26 @@
exit(-1);
} else
printf("ok: matches expected msg\n");
- msgb_free(msg);
expect_tx_msg = NULL;
return 0;
}
-static int rx_pdu(struct osmo_iuup_cn *cn, struct msgb *msg, void *pdu_priv)
+static int rx_pdu(struct osmo_iuup_cn *cn, struct msgb *msg)
{
int rc;
printf(" -PDU-> [IuUP]\n");
printf("%s\n", dump(msg));
- printf("pdu_priv=%p\n", pdu_priv);
- rc = osmo_iuup_cn_rx_pdu(cn, msg, pdu_priv);
+ rc = osmo_iuup_cn_rx_pdu(cn, msg);
printf("rc=%d\n", rc);
return rc;
}
-static int tx_payload(struct osmo_iuup_cn *cn, struct msgb *msg, void *pdu_priv)
+static int tx_payload(struct osmo_iuup_cn *cn, struct msgb *msg)
{
int rc;
printf(" [IuUP] <-RTP-\n");
printf("%s\n", dump(msg));
- printf("pdu_priv=%p\n", pdu_priv);
- rc = osmo_iuup_cn_tx_payload(cn, msg, pdu_priv);
+ rc = osmo_iuup_cn_tx_payload(cn, msg);
printf("rc=%d\n", rc);
return rc;
}
@@ -91,7 +87,6 @@
void test_cn_session()
{
void *node_priv = (void*)0x2342;
- void *pdu_priv = (void*)0xfeed;
struct osmo_iuup_cn_cfg cfg = {
.node_priv = node_priv,
@@ -103,13 +98,13 @@
OSMO_ASSERT(cn);
printf("\nSend IuUP Initialization. Expecting direct tx_msg() of the Initialization Ack\n");
- expect_tx_msg = "e400240000";
+ expect_tx_msg = "8060dc5219495e3f00010111" /* RTP header */
+ "e4002400"; /* IuUP Init Ack */
rx_pdu(cn,
msgb_from_hex("IuUP-Init",
"8060dc5219495e3f00010111" /* <- RTP header */
"e000df99" /* <- IuUP header */
- "160051673c01270000820000001710000100" /* IuUP params */),
- pdu_priv);
+ "160051673c01270000820000001710000100" /* IuUP params */));
#define RTP_HEADER "8060944c6256042c00010102"
#define IUUP_HEADER "0100e2b3"
@@ -119,28 +114,23 @@
expect_rx_payload = RTP_HEADER RTP_PAYLOAD;
rx_pdu(cn,
msgb_from_hex("IuUP-Data",
- RTP_HEADER IUUP_HEADER RTP_PAYLOAD),
- pdu_priv);
+ RTP_HEADER IUUP_HEADER RTP_PAYLOAD));
printf("\nTransmit RTP. Expecting tx_msg() with inserted IuUP header\n");
expect_tx_msg = RTP_HEADER "000002b3" RTP_PAYLOAD;
tx_payload(cn,
- msgb_from_hex("RTP data", RTP_HEADER RTP_PAYLOAD),
- pdu_priv);
+ msgb_from_hex("RTP data", RTP_HEADER RTP_PAYLOAD));
printf("\nMore RTP, each time the Frame Nr advances, causing a new header CRC.\n");
expect_tx_msg = RTP_HEADER "0100e2b3" RTP_PAYLOAD;
tx_payload(cn,
- msgb_from_hex("RTP data", RTP_HEADER RTP_PAYLOAD),
- pdu_priv);
+ msgb_from_hex("RTP data", RTP_HEADER RTP_PAYLOAD));
expect_tx_msg = RTP_HEADER "02007eb3" RTP_PAYLOAD;
tx_payload(cn,
- msgb_from_hex("RTP data", RTP_HEADER RTP_PAYLOAD),
- pdu_priv);
+ msgb_from_hex("RTP data", RTP_HEADER RTP_PAYLOAD));
expect_tx_msg = RTP_HEADER "03009eb3" RTP_PAYLOAD;
tx_payload(cn,
- msgb_from_hex("RTP data", RTP_HEADER RTP_PAYLOAD),
- pdu_priv);
+ msgb_from_hex("RTP data", RTP_HEADER RTP_PAYLOAD));
printf("All done.\n");
}
diff --git a/tests/iuup/iuup_test.ok b/tests/iuup/iuup_test.ok
index fa46635..2b09c66 100644
--- a/tests/iuup/iuup_test.ok
+++ b/tests/iuup/iuup_test.ok
@@ -2,11 +2,10 @@
Send IuUP Initialization. Expecting direct tx_msg() of the Initialization Ack
-PDU-> [IuUP]
8060dc5219495e3f00010111e000df99160051673c01270000820000001710000100
-pdu_priv=0xfeed
tx_msg() invoked by iuup_cn!
<-PDU- [IuUP]
-e400240000
-node_priv=0x2342 pdu_priv=0xfeed
+8060dc5219495e3f00010111e4002400
+node_priv=0x2342
ok: matches expected msg
rc=0
@@ -14,51 +13,46 @@
i.e. should strip away 0100e2b3
-PDU-> [IuUP]
8060944c6256042c000101020100e2b36cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
-pdu_priv=0xfeed
rx_payload() invoked by iuup_cn!
[IuUP] -RTP->
8060944c6256042c000101026cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
-node_priv=0x2342 pdu_priv=0xfeed
+node_priv=0x2342
ok: matches expected msg
rc=0
Transmit RTP. Expecting tx_msg() with inserted IuUP header
[IuUP] <-RTP-
8060944c6256042c000101026cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
-pdu_priv=0xfeed
tx_msg() invoked by iuup_cn!
<-PDU- [IuUP]
8060944c6256042c00010102000002b36cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
-node_priv=0x2342 pdu_priv=0xfeed
+node_priv=0x2342
ok: matches expected msg
rc=0
More RTP, each time the Frame Nr advances, causing a new header CRC.
[IuUP] <-RTP-
8060944c6256042c000101026cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
-pdu_priv=0xfeed
tx_msg() invoked by iuup_cn!
<-PDU- [IuUP]
8060944c6256042c000101020100e2b36cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
-node_priv=0x2342 pdu_priv=0xfeed
+node_priv=0x2342
ok: matches expected msg
rc=0
[IuUP] <-RTP-
8060944c6256042c000101026cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
-pdu_priv=0xfeed
tx_msg() invoked by iuup_cn!
<-PDU- [IuUP]
8060944c6256042c0001010202007eb36cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
-node_priv=0x2342 pdu_priv=0xfeed
+node_priv=0x2342
ok: matches expected msg
rc=0
[IuUP] <-RTP-
8060944c6256042c000101026cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
-pdu_priv=0xfeed
tx_msg() invoked by iuup_cn!
<-PDU- [IuUP]
8060944c6256042c0001010203009eb36cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
-node_priv=0x2342 pdu_priv=0xfeed
+node_priv=0x2342
ok: matches expected msg
rc=0
All done.