Initially implement the new osmo-mgw and libosmo-mgcp

Leave the old osmo-bsc_mgcp and libosmo-legacy-mgcp as it is; on a copy thereof
(added by a previous commit), apply changes to initially implement the new
osmo-mgw.

Adjust build system and debian packaging to accomodate the new libosmo-mgcp and
osmo-mgw.

The main differences:

*) use a list to manage rtp connections.

Aggregate all rtp related information inside a single struct.

Use a linked list to manage the both connections (net and bts).
The idea behind using a list is that we might support conference
calls at some later point.

Store the linked list in struct mgcp_endpoint, have a private linked
list for each endpoint. The list contains connection items which are
implemented in struct mgcp_conn. A connection is allocated and freed
using the functions in mgcp_conn.c. A connection is allocated on the
reception of a CRCX command and freed with the reception of a DLCX
command.

*) remove external transcoder feature

Fortunatelly the external transcoder feature is not needed
anymore. This patch removes the related code.

*) vty: get rid of CONN_BTS and CONN_NET

Since the new connection model does not make a difference
between BTS and NET connections the VTY should not use
the fixed CONN_BTS and CONN_NET constants.

- Handle the conns list inside the endpoint directly
- introduce function to dump basic rtp connection info
- introduce human readable names for connections

Parts of the code adjusted to use generalized connections instead of explicit
BTS/NET ones:

- teach mgcp_send_dummy() to send dummy packets to any RTP connection
- network: generalize mgcp_bind_net/bts_rtp_port()
- network: generalize mgcp_send()
- tap: generalize call tapping feature
- stat: generalize statistics
- Replace rtp_data_net() and rtp_data_bts() with generalized rtp_data_rx()

*) mgcp_protocol.c fixes:

- check ci string before it is converted:
  In case of missing ci, a nullpointer is delivered to strtoul().
  Add a function that takes ci, checks it and converts it to an
  uint32_t. Use the return code to react on missing ci.
- output error message on missing CI.
- when parsing the mode, print log message when mode is missing.
- use mode_orig when mode is missing.
- fix ptime formatstring to use %u rather than %d.
- cosmetic: log when connection is deleted on DLCX.
- change loglevels of CRCX, MDCX, DLCX events from DEBUG to NOTICE.

*) mgcp_test

- apply rename of strline_r() to mgcp_strline().
- MGCP command macros:
  - Add 'I: 1' parameters.
  - Use proper port numbers:
    from m=audio 0 RTP/AVP 126
    to   m=audio 16002 RTP/AVP 128
  - Change ptime to 'a=ptime:40' because this is what the MGW currently
    returns.  CRCX generally feed a ptime:40 and this is expected to be
    returned.
- struct mgcp_test: Use only one ptype, there are no explicit BTS and NET
  endpoints anymore.
  Hence remove one column from tests[].
- test_messages():
  - Enable: remove '#if 0'
  - Remove concept of BTS and NET endpoints: test only one conn, as they are
    now interchangeable anyway.
  - remove endpoint init, now done internally.
  - add false asserts in error cases.
- test_retransmission():
  - remove endpoint init, now done internally.
  - add false asserts in error cases.
- test_packet_error_detection():
  - Remove concept of BTS and NET endpoints: test only one conn, as they are
    now interchangeable anyway. Use arbitrary conn ids (e.g. 4711).
  - remove endpoint init, now done internally.
  - add false assert in error case.
  - Assert that a conn really vanishes on DLCX, previously the conn would
    remain and just be unused, now it is actually discarded.
- test_no_cycle()
  - Remove concept of BTS and NET endpoints: test only one conn, as they are
    now interchangeable anyway. Use arbitrary conn ids (e.g. 4711).
- test_no_name()
  - Enable: remove '#if 0'.
  - remove endpoint init, now done internally.
  - add false assert in error case.
- mgcp_test.ok: adjust expected results to status quo:
  - We now see two dummy packets instead of one, now sent to both sides because
    we don't know of BTS or NET side. (maybe drop dummy packets later...)
  - packet duration, conn mode: now sane defaults show instead of unset.
- various whitespace and formatting changes from lindent.

Change-Id: Ie008599136c7ed8a0dfbb0cf803188975a499fc5
diff --git a/src/libosmo-mgcp/mgcp_osmux.c b/src/libosmo-mgcp/mgcp_osmux.c
index 743d3f9..60ffe06 100644
--- a/src/libosmo-mgcp/mgcp_osmux.c
+++ b/src/libosmo-mgcp/mgcp_osmux.c
@@ -20,9 +20,10 @@
 #include <osmocom/netif/osmux.h>
 #include <osmocom/netif/rtp.h>
 
-#include <osmocom/legacy_mgcp/mgcp.h>
-#include <osmocom/legacy_mgcp/mgcp_internal.h>
-#include <osmocom/legacy_mgcp/osmux.h>
+#include <osmocom/mgcp/mgcp.h>
+#include <osmocom/mgcp/mgcp_internal.h>
+#include <osmocom/mgcp/osmux.h>
+#include <osmocom/mgcp/mgcp_conn.h>
 
 static struct osmo_fd osmux_fd;
 
@@ -38,7 +39,8 @@
 
 static void *osmux;
 
-static void osmux_deliver(struct msgb *batch_msg, void *data)
+/* Deliver OSMUX batch to the remote end */
+static void osmux_deliver_cb(struct msgb *batch_msg, void *data)
 {
 	struct osmux_handle *handle = data;
 	struct sockaddr_in out = {
@@ -52,12 +54,12 @@
 	msgb_free(batch_msg);
 }
 
+/* Lookup existing OSMUX handle for specified destination address. */
 static struct osmux_handle *
 osmux_handle_find_get(struct in_addr *addr, int rem_port)
 {
 	struct osmux_handle *h;
 
-	/* Lookup for existing OSMUX handle for this destination address. */
 	llist_for_each_entry(h, &osmux_handle_list, head) {
 		if (memcmp(&h->rem_addr, addr, sizeof(struct in_addr)) == 0 &&
 		    h->rem_port == rem_port) {
@@ -72,11 +74,11 @@
 	return NULL;
 }
 
+/* Put down no longer needed OSMUX handle */
 static void osmux_handle_put(struct osmux_in_handle *in)
 {
 	struct osmux_handle *h;
 
-	/* Lookup for existing OSMUX handle for this destination address. */
 	llist_for_each_entry(h, &osmux_handle_list, head) {
 		if (h->in == in) {
 			if (--h->refcnt == 0) {
@@ -101,6 +103,7 @@
 	LOGP(DLMGCP, LOGL_ERROR, "cannot find Osmux input handle %p\n", in);
 }
 
+/* Allocate free OSMUX handle */
 static struct osmux_handle *
 osmux_handle_alloc(struct mgcp_config *cfg, struct in_addr *addr, int rem_port)
 {
@@ -119,11 +122,14 @@
 		return NULL;
 	}
 
-	h->in->osmux_seq = 0; /* sequence number to start OSmux message from */
+	/* sequence number to start OSMUX message from */
+	h->in->osmux_seq = 0;
+
 	h->in->batch_factor = cfg->osmux_batch;
+
 	/* If batch size is zero, the library defaults to 1470 bytes. */
 	h->in->batch_size = cfg->osmux_batch_size;
-	h->in->deliver = osmux_deliver;
+	h->in->deliver = osmux_deliver_cb;
 	osmux_xfrm_input_init(h->in);
 	h->in->data = h;
 
@@ -135,6 +141,8 @@
 	return h;
 }
 
+/* Lookup existing handle for a specified address, if the handle can not be
+ * foud a the function will automatically allocate one */
 static struct osmux_in_handle *
 osmux_handle_lookup(struct mgcp_config *cfg, struct in_addr *addr, int rem_port)
 {
@@ -151,47 +159,60 @@
 	return h->in;
 }
 
-int osmux_xfrm_to_osmux(int type, char *buf, int rc, struct mgcp_endpoint *endp)
+/*! send RTP packet through OSMUX connection.
+ *  \param[in] buf rtp data
+ *  \param[in] buf_len length of rtp data
+ *  \param[in] conn associated RTP connection
+ *  \returns 0 on success, -1 on ERROR */
+int osmux_xfrm_to_osmux(char *buf, int buf_len, struct mgcp_conn_rtp *conn)
 {
 	int ret;
 	struct msgb *msg;
 
 	msg = msgb_alloc(4096, "RTP");
 	if (!msg)
-		return 0;
+		return -1;
 
-	memcpy(msg->data, buf, rc);
-	msgb_put(msg, rc);
+	memcpy(msg->data, buf, buf_len);
+	msgb_put(msg, buf_len);
 
-	while ((ret = osmux_xfrm_input(endp->osmux.in, msg, endp->osmux.cid)) > 0) {
+	while ((ret = osmux_xfrm_input(conn->osmux.in, msg, conn->osmux.cid)) > 0) {
 		/* batch full, build and deliver it */
-		osmux_xfrm_input_deliver(endp->osmux.in);
+		osmux_xfrm_input_deliver(conn->osmux.in);
 	}
 	return 0;
 }
 
+/* Lookup the endpoint that corresponds to the specified address (port) */
 static struct mgcp_endpoint *
 endpoint_lookup(struct mgcp_config *cfg, int cid,
 		struct in_addr *from_addr, int type)
 {
-	struct mgcp_endpoint *tmp = NULL;
+	struct mgcp_endpoint *endp = NULL;
 	int i;
+	struct mgcp_conn_rtp *conn_net = NULL;
+	struct mgcp_conn_rtp *conn_bts = NULL;
 
-	/* Lookup for the endpoint that corresponds to this port */
 	for (i=0; i<cfg->trunk.number_endpoints; i++) {
 		struct in_addr *this;
 
-		tmp = &cfg->trunk.endpoints[i];
+		endp = &cfg->trunk.endpoints[i];
 
+#if 0
 		if (!tmp->allocated)
 			continue;
+#endif
 
 		switch(type) {
 		case MGCP_DEST_NET:
-			this = &tmp->net_end.addr;
+			/* FIXME: Get rid of CONN_ID_XXX! */
+			conn_net = mgcp_conn_get_rtp(endp, CONN_ID_NET);
+			this = &conn_net->end.addr;
 			break;
 		case MGCP_DEST_BTS:
-			this = &tmp->bts_end.addr;
+			/* FIXME: Get rid of CONN_ID_XXX! */
+			conn_bts = mgcp_conn_get_rtp(endp, CONN_ID_BTS);
+			this = &conn_bts->end.addr;
 			break;
 		default:
 			/* Should not ever happen */
@@ -199,8 +220,10 @@
 			return NULL;
 		}
 
-		if (tmp->osmux.cid == cid && this->s_addr == from_addr->s_addr)
-			return tmp;
+		/* FIXME: Get rid of CONN_ID_XXX! */
+		conn_net = mgcp_conn_get_rtp(endp, CONN_ID_NET);
+		if (conn_net->osmux.cid == cid && this->s_addr == from_addr->s_addr)
+			return endp;
 	}
 
 	LOGP(DLMGCP, LOGL_ERROR, "Cannot find endpoint with cid=%d\n", cid);
@@ -211,30 +234,54 @@
 static void scheduled_tx_net_cb(struct msgb *msg, void *data)
 {
 	struct mgcp_endpoint *endp = data;
+	struct mgcp_conn_rtp *conn_net = NULL;
+	struct mgcp_conn_rtp *conn_bts = NULL;
+
+	/* FIXME: Get rid of CONN_ID_XXX! */
+	conn_bts = mgcp_conn_get_rtp(endp, CONN_ID_BTS);
+	conn_net = mgcp_conn_get_rtp(endp, CONN_ID_NET);
+	if (!conn_bts || !conn_net)
+		return;
+
 	struct sockaddr_in addr = {
-		.sin_addr = endp->net_end.addr,
-		.sin_port = endp->net_end.rtp_port,
+		.sin_addr = conn_net->end.addr,
+		.sin_port = conn_net->end.rtp_port,
 	};
 
-	endp->bts_end.octets += msg->len;
-	endp->bts_end.packets++;
+	conn_bts->end.octets_tx += msg->len;
+	conn_bts->end.packets_tx++;
 
-	mgcp_send(endp, MGCP_DEST_NET, 1, &addr, (char *)msg->data, msg->len);
+	/* Send RTP data to NET */
+	/* FIXME: Get rid of conn_bts and conn_net! */
+	mgcp_send(endp, 1, &addr, (char *)msg->data, msg->len,
+		  conn_bts, conn_net);
 	msgb_free(msg);
 }
 
 static void scheduled_tx_bts_cb(struct msgb *msg, void *data)
 {
 	struct mgcp_endpoint *endp = data;
+	struct mgcp_conn_rtp *conn_net = NULL;
+	struct mgcp_conn_rtp *conn_bts = NULL;
+
+	/* FIXME: Get rid of CONN_ID_XXX! */
+	conn_bts = mgcp_conn_get_rtp(endp, CONN_ID_BTS);
+	conn_net = mgcp_conn_get_rtp(endp, CONN_ID_NET);
+	if (!conn_bts || !conn_net)
+		return;
+
 	struct sockaddr_in addr = {
-		.sin_addr = endp->bts_end.addr,
-		.sin_port = endp->bts_end.rtp_port,
+		.sin_addr = conn_bts->end.addr,
+		.sin_port = conn_bts->end.rtp_port,
 	};
 
-	endp->net_end.octets += msg->len;
-	endp->net_end.packets++;
+	conn_net->end.octets_tx += msg->len;
+	conn_net->end.packets_tx++;
 
-	mgcp_send(endp, MGCP_DEST_BTS, 1, &addr, (char *)msg->data, msg->len);
+	/* Send RTP data to BTS */
+	/* FIXME: Get rid of conn_bts and conn_net! */
+	mgcp_send(endp, 1, &addr, (char *)msg->data, msg->len,
+		  conn_net, conn_bts);
 	msgb_free(msg);
 }
 
@@ -271,6 +318,7 @@
 	struct sockaddr_in addr;
 	struct mgcp_config *cfg = ofd->data;
 	uint32_t rem;
+	struct mgcp_conn_rtp *conn_net = NULL;
 
 	msg = osmux_recv(ofd, &addr);
 	if (!msg)
@@ -287,17 +335,23 @@
 		/* Yes, we use MGCP_DEST_NET to locate the origin */
 		endp = endpoint_lookup(cfg, osmuxh->circuit_id,
 				       &addr.sin_addr, MGCP_DEST_NET);
+
+		/* FIXME: Get rid of CONN_ID_XXX! */
+		conn_net = mgcp_conn_get_rtp(endp, CONN_ID_NET);
+		if (!conn_net)
+			goto out;
+
 		if (!endp) {
 			LOGP(DLMGCP, LOGL_ERROR,
 			     "Cannot find an endpoint for circuit_id=%d\n",
 			     osmuxh->circuit_id);
 			goto out;
 		}
-		endp->osmux.stats.octets += osmux_chunk_length(msg, rem);
-		endp->osmux.stats.chunks++;
+		conn_net->osmux.stats.octets += osmux_chunk_length(msg, rem);
+		conn_net->osmux.stats.chunks++;
 		rem = msg->len;
 
-		osmux_xfrm_output(osmuxh, &endp->osmux.out, &list);
+		osmux_xfrm_output(osmuxh, &conn_net->osmux.out, &list);
 		osmux_tx_sched(&list, scheduled_tx_bts_cb, endp);
 	}
 out:
@@ -311,6 +365,7 @@
 {
 	struct mgcp_endpoint *endp;
 	uint8_t osmux_cid;
+	struct mgcp_conn_rtp *conn_net = NULL;
 
 	if (msg->len < 1 + sizeof(osmux_cid)) {
 		LOGP(DLMGCP, LOGL_ERROR,
@@ -337,10 +392,14 @@
 		goto out;
 	}
 
-	if (endp->osmux.state == OSMUX_STATE_ENABLED)
+	conn_net = mgcp_conn_get_rtp(endp, CONN_ID_NET);
+	if (!conn_net)
 		goto out;
 
-	if (osmux_enable_endpoint(endp, &addr->sin_addr, addr->sin_port) < 0 ) {
+	if (conn_net->osmux.state == OSMUX_STATE_ENABLED)
+		goto out;
+
+	if (osmux_enable_conn(endp, conn_net, &addr->sin_addr, addr->sin_port) < 0 ) {
 		LOGP(DLMGCP, LOGL_ERROR,
 		     "Could not enable osmux in endpoint %d\n",
 		     ENDPOINT_NUMBER(endp));
@@ -363,6 +422,7 @@
 	struct sockaddr_in addr;
 	struct mgcp_config *cfg = ofd->data;
 	uint32_t rem;
+	struct mgcp_conn_rtp *conn_net = NULL;
 
 	msg = osmux_recv(ofd, &addr);
 	if (!msg)
@@ -379,17 +439,23 @@
 		/* Yes, we use MGCP_DEST_BTS to locate the origin */
 		endp = endpoint_lookup(cfg, osmuxh->circuit_id,
 				       &addr.sin_addr, MGCP_DEST_BTS);
+
+		/* FIXME: Get rid of CONN_ID_XXX! */
+		conn_net = mgcp_conn_get_rtp(endp, CONN_ID_NET);
+		if (!conn_net)
+			goto out;
+
 		if (!endp) {
 			LOGP(DLMGCP, LOGL_ERROR,
 			     "Cannot find an endpoint for circuit_id=%d\n",
 			     osmuxh->circuit_id);
 			goto out;
 		}
-		endp->osmux.stats.octets += osmux_chunk_length(msg, rem);
-		endp->osmux.stats.chunks++;
+		conn_net->osmux.stats.octets += osmux_chunk_length(msg, rem);
+		conn_net->osmux.stats.chunks++;
 		rem = msg->len;
 
-		osmux_xfrm_output(osmuxh, &endp->osmux.out, &list);
+		osmux_xfrm_output(osmuxh, &conn_net->osmux.out, &list);
 		osmux_tx_sched(&list, scheduled_tx_net_cb, endp);
 	}
 out:
@@ -432,116 +498,155 @@
 	return 0;
 }
 
-int osmux_enable_endpoint(struct mgcp_endpoint *endp, struct in_addr *addr, uint16_t port)
+/*! enable OSXMUX circuit for a specified connection.
+ *  \param[in] endp mgcp endpoint (configuration)
+ *  \param[in] conn connection to disable
+ *  \param[in] addr IP address of remote OSMUX endpoint
+ *  \param[in] port portnumber of the remote OSMUX endpoint
+ *  \returns 0 on success, -1 on ERROR */
+int osmux_enable_conn(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
+		      struct in_addr *addr, uint16_t port)
 {
-	/* If osmux is enabled, initialize the output handler. This handler is
-	 * used to reconstruct the RTP flow from osmux. The RTP SSRC is
-	 * allocated based on the circuit ID (endp->osmux.cid), which is unique
-	 * in the local scope to the BSC/BSC-NAT. We use it to divide the RTP
-	 * SSRC space (2^32) by the 256 possible circuit IDs, then randomly
-	 * select one value from that window. Thus, we have no chance to have
-	 * overlapping RTP SSRC traveling to the BTSes behind the BSC,
-	 * similarly, for flows traveling to the MSC.
+	/*! If osmux is enabled, initialize the output handler. This handler is
+	 *  used to reconstruct the RTP flow from osmux. The RTP SSRC is
+	 *  allocated based on the circuit ID (conn_net->osmux.cid), which is unique
+	 *  in the local scope to the BSC/BSC-NAT. We use it to divide the RTP
+	 *  SSRC space (2^32) by the 256 possible circuit IDs, then randomly
+	 *  select one value from that window. Thus, we have no chance to have
+	 *  overlapping RTP SSRC traveling to the BTSes behind the BSC,
+	 *  similarly, for flows traveling to the MSC.
 	 */
 	static const uint32_t rtp_ssrc_winlen = UINT32_MAX / 256;
+	uint16_t osmux_dummy = endp->cfg->osmux_dummy;
 
-	if (endp->osmux.state == OSMUX_STATE_DISABLED) {
-		LOGP(DLMGCP, LOGL_ERROR, "Endpoint %u didn't request Osmux\n",
-		     ENDPOINT_NUMBER(endp));
+	/* Check if osmux is enabled for the specified connection */
+	if (conn->osmux.state == OSMUX_STATE_DISABLED) {
+		LOGP(DLMGCP, LOGL_ERROR, "OSMUX not enabled for conn:%s\n",
+		     mgcp_conn_dump(conn->conn));
 		return -1;
 	}
 
-	osmux_xfrm_output_init(&endp->osmux.out,
-			       (endp->osmux.cid * rtp_ssrc_winlen) +
+	osmux_xfrm_output_init(&conn->osmux.out,
+			       (conn->osmux.cid * rtp_ssrc_winlen) +
 			       (random() % rtp_ssrc_winlen));
 
-	endp->osmux.in = osmux_handle_lookup(endp->cfg, addr, port);
-	if (!endp->osmux.in) {
-		LOGP(DLMGCP, LOGL_ERROR, "Cannot allocate input osmux handle\n");
+	conn->osmux.in = osmux_handle_lookup(endp->cfg, addr, port);
+	if (!conn->osmux.in) {
+		LOGP(DLMGCP, LOGL_ERROR, "Cannot allocate input osmux handle for conn:%s\n",
+		     mgcp_conn_dump(conn->conn));
 		return -1;
 	}
-	if (!osmux_xfrm_input_open_circuit(endp->osmux.in, endp->osmux.cid,
-					   endp->cfg->osmux_dummy)) {
-		LOGP(DLMGCP, LOGL_ERROR, "Cannot open osmux circuit %u\n",
-		     endp->osmux.cid);
+	if (!osmux_xfrm_input_open_circuit(conn->osmux.in, conn->osmux.cid, osmux_dummy)) {
+		LOGP(DLMGCP, LOGL_ERROR, "Cannot open osmux circuit %u for conn:%s\n",
+		     conn->osmux.cid, mgcp_conn_dump(conn->conn));
 		return -1;
 	}
 
 	switch (endp->cfg->role) {
 		case MGCP_BSC_NAT:
-			endp->type = MGCP_OSMUX_BSC_NAT;
+			conn->type = MGCP_OSMUX_BSC_NAT;
 			break;
 		case MGCP_BSC:
-			endp->type = MGCP_OSMUX_BSC;
+			conn->type = MGCP_OSMUX_BSC;
 			break;
 	}
-	endp->osmux.state = OSMUX_STATE_ENABLED;
+
+	conn->osmux.state = OSMUX_STATE_ENABLED;
 
 	return 0;
 }
 
-void osmux_disable_endpoint(struct mgcp_endpoint *endp)
+/*! disable OSXMUX circuit for a specified connection.
+ *  \param[in] conn connection to disable */
+void osmux_disable_conn(struct mgcp_conn_rtp *conn)
 {
-	LOGP(DLMGCP, LOGL_INFO, "Releasing endpoint %u using Osmux CID %u\n",
-	     ENDPOINT_NUMBER(endp), endp->osmux.cid);
-	osmux_xfrm_input_close_circuit(endp->osmux.in, endp->osmux.cid);
-	endp->osmux.state = OSMUX_STATE_DISABLED;
-	endp->osmux.cid = -1;
-	osmux_handle_put(endp->osmux.in);
+	if (!conn)
+		return;
+
+	if (conn->osmux.state != OSMUX_STATE_ENABLED)
+		return;
+
+	LOGP(DLMGCP, LOGL_INFO, "Releasing connection %u using Osmux CID %u\n",
+	     conn->conn->id, conn->osmux.cid);
+	osmux_xfrm_input_close_circuit(conn->osmux.in, conn->osmux.cid);
+	conn->osmux.state = OSMUX_STATE_DISABLED;
+	conn->osmux.cid = -1;
+	osmux_handle_put(conn->osmux.in);
 }
 
-void osmux_release_cid(struct mgcp_endpoint *endp)
+/*! relase OSXMUX cid, that had been allocated to this connection.
+ *  \param[in] conn connection with OSMUX cid to release */
+void osmux_release_cid(struct mgcp_conn_rtp *conn)
 {
-	if (endp->osmux.allocated_cid >= 0)
-		osmux_put_cid(endp->osmux.allocated_cid);
-	endp->osmux.allocated_cid = -1;
+	if (!conn)
+		return;
+
+	if (conn->osmux.state != OSMUX_STATE_ENABLED)
+		return;
+
+	if (conn->osmux.allocated_cid >= 0)
+		osmux_put_cid(conn->osmux.allocated_cid);
+	conn->osmux.allocated_cid = -1;
 }
 
-void osmux_allocate_cid(struct mgcp_endpoint *endp)
+/*! allocate OSXMUX cid to connection.
+ *  \param[in] conn connection for which we allocate the OSMUX cid*/
+void osmux_allocate_cid(struct mgcp_conn_rtp *conn)
 {
-	osmux_release_cid(endp);
-	endp->osmux.allocated_cid = osmux_get_cid();
+	osmux_release_cid(conn);
+	conn->osmux.allocated_cid = osmux_get_cid();
 }
 
-/* We don't need to send the dummy load for osmux so often as another endpoint
- * may have already punched the hole in the firewall. This approach is simple
- * though.
- */
-int osmux_send_dummy(struct mgcp_endpoint *endp)
+/*! send RTP dummy packet to OSMUX connection port.
+ *  \param[in] endp mcgp endpoint that holds the RTP connection
+ *  \param[in] conn associated RTP connection
+ *  \returns bytes sent, -1 on error */
+int osmux_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
 {
 	char buf[1 + sizeof(uint8_t)];
 	struct in_addr addr_unset = {};
 
+	/*! The dummy packet will not be sent via the actual OSMUX connection,
+	 *  instead it is sent out of band to port where the remote OSMUX
+	 *  multplexer is listening. The goal is to ensure that the connection
+	 *  is kept open */
+
+	/*! We don't need to send the dummy load for osmux so often as another
+	 *  endpoint may have already punched the hole in the firewall. This
+	 *  approach is simple though. */
+
 	buf[0] = MGCP_DUMMY_LOAD;
-	memcpy(&buf[1], &endp->osmux.cid, sizeof(endp->osmux.cid));
+	memcpy(&buf[1], &conn->osmux.cid, sizeof(conn->osmux.cid));
 
 	/* Wait until we have the connection information from MDCX */
-	if (memcmp(&endp->net_end.addr, &addr_unset, sizeof(addr_unset)) == 0)
+	if (memcmp(&conn->end.addr, &addr_unset, sizeof(addr_unset)) == 0)
 		return 0;
 
-	if (endp->osmux.state == OSMUX_STATE_ACTIVATING) {
-		if (osmux_enable_endpoint(endp, &endp->net_end.addr,
-					  htons(endp->cfg->osmux_port)) < 0) {
+	if (conn->osmux.state == OSMUX_STATE_ACTIVATING) {
+		if (osmux_enable_conn(endp, conn, &conn->end.addr,
+				      htons(endp->cfg->osmux_port)) < 0) {
 			LOGP(DLMGCP, LOGL_ERROR,
-			     "Could not activate osmux in endpoint %d\n",
-			     ENDPOINT_NUMBER(endp));
+			     "Could not activate osmux for conn:%s\n",
+			     mgcp_conn_dump(conn->conn));
 		}
 		LOGP(DLMGCP, LOGL_ERROR,
 		     "Osmux CID %u for %s:%u is now enabled\n",
-		     endp->osmux.cid, inet_ntoa(endp->net_end.addr),
+		     conn->osmux.cid, inet_ntoa(conn->end.addr),
 		     endp->cfg->osmux_port);
 	}
 	LOGP(DLMGCP, LOGL_DEBUG,
 	     "sending OSMUX dummy load to %s CID %u\n",
-	     inet_ntoa(endp->net_end.addr), endp->osmux.cid);
+	     inet_ntoa(conn->end.addr), conn->osmux.cid);
 
-	return mgcp_udp_send(osmux_fd.fd, &endp->net_end.addr,
+	return mgcp_udp_send(osmux_fd.fd, &conn->end.addr,
 			     htons(endp->cfg->osmux_port), buf, sizeof(buf));
 }
 
-/* bsc-nat allocates/releases the Osmux circuit ID */
+/*! bsc-nat allocates/releases the OSMUX cids (Circuit IDs). */
 static uint8_t osmux_cid_bitmap[(OSMUX_CID_MAX + 1) / 8];
 
+/*! count the number of taken OSMUX cids.
+ *  \returns number of OSMUX cids in use */
 int osmux_used_cid(void)
 {
 	int i, j, used = 0;
@@ -556,6 +661,8 @@
 	return used;
 }
 
+/*! take a free OSMUX cid.
+ *  \returns OSMUX cid */
 int osmux_get_cid(void)
 {
 	int i, j;
@@ -576,6 +683,8 @@
 	return -1;
 }
 
+/*! put back a no longer used OSMUX cid.
+ *  \param[in] osmux_cid OSMUX cid */
 void osmux_put_cid(uint8_t osmux_cid)
 {
 	LOGP(DLMGCP, LOGL_DEBUG, "Osmux CID %u is back to the pool\n", osmux_cid);