wip
Change-Id: I4fdcebf3b006a72c5318a9105a2be2cc7057dca1
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.