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_protocol.c b/src/libosmo-mgcp/mgcp_protocol.c
index bc1ec0d..ac25894 100644
--- a/src/libosmo-mgcp/mgcp_protocol.c
+++ b/src/libosmo-mgcp/mgcp_protocol.c
@@ -33,19 +33,15 @@
 #include <osmocom/core/talloc.h>
 #include <osmocom/core/select.h>
 
-#include <osmocom/legacy_mgcp/mgcp.h>
-#include <osmocom/legacy_mgcp/mgcp_internal.h>
-
-#define for_each_non_empty_line(line, save)			\
-	for (line = strtok_r(NULL, "\r\n", &save); line;\
-	     line = strtok_r(NULL, "\r\n", &save))
-
-
-static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end);
+#include <osmocom/mgcp/mgcp.h>
+#include <osmocom/mgcp/mgcp_internal.h>
+#include <osmocom/mgcp/mgcp_stat.h>
+#include <osmocom/mgcp/mgcp_msg.h>
+#include <osmocom/mgcp/mgcp_ep.h>
 
 struct mgcp_request {
 	char *name;
-	struct msgb *(*handle_request) (struct mgcp_parse_data *data);
+	struct msgb *(*handle_request) (struct mgcp_parse_data * data);
 	char *debug_name;
 };
 
@@ -59,111 +55,67 @@
 static struct msgb *handle_rsip(struct mgcp_parse_data *data);
 static struct msgb *handle_noti_req(struct mgcp_parse_data *data);
 
-static void create_transcoder(struct mgcp_endpoint *endp);
-static void delete_transcoder(struct mgcp_endpoint *endp);
-
-static int setup_rtp_processing(struct mgcp_endpoint *endp);
-
-static int mgcp_analyze_header(struct mgcp_parse_data *parse, char *data);
-
-/* Display an mgcp message on the log output */
-void display_mgcp_message(unsigned char *message, unsigned int len,
-			  char *preamble)
+/* Initalize transcoder */
+static int setup_rtp_processing(struct mgcp_endpoint *endp,
+				struct mgcp_conn_rtp *conn)
 {
-	unsigned char line[80];
-	unsigned char *ptr;
-	unsigned int consumed = 0;
-	unsigned int consumed_line = 0;
-	unsigned int line_count = 0;
+	struct mgcp_config *cfg = endp->cfg;
+	struct mgcp_conn_rtp *conn_src = NULL;
+	struct mgcp_conn_rtp *conn_dst = conn;
+	struct mgcp_conn *_conn;
 
-	if (!log_check_level(DLMGCP, LOGL_DEBUG))
-		return;
-
-	while (1) {
-		memset(line, 0, sizeof(line));
-		ptr = line;
-		consumed_line = 0;
-		do {
-			if (*message != '\n' && *message != '\r') {
-				*ptr = *message;
-				ptr++;
-			}
-			message++;
-			consumed++;
-			consumed_line++;
-		} while (*message != '\n' && consumed < len
-			 && consumed_line < sizeof(line));
-
-		if (strlen((const char *)line)) {
-			LOGP(DLMGCP, LOGL_DEBUG, "%s: line #%02u: %s\n",
-			     preamble, line_count, line);
-			line_count++;
-		}
-
-		if (consumed >= len)
-			return;
-	}
-}
-
-static int mgcp_check_param(const struct mgcp_endpoint *endp, const char *line)
-{
-	const size_t line_len = strlen(line);
-	if (line[0] != '\0' && line_len < 2) {
-		LOGP(DLMGCP, LOGL_ERROR,
-			"Wrong MGCP option format: '%s' on 0x%x\n",
-			line, ENDPOINT_NUMBER(endp));
+	if (conn->type != MGCP_RTP_DEFAULT) {
+		LOGP(DLMGCP, LOGL_NOTICE,
+		     "endpoint:%x RTP-setup: Endpoint is not configured as RTP default, stopping here!\n",
+		     ENDPOINT_NUMBER(endp));
 		return 0;
 	}
 
-	return 1;
+	if (conn->conn->mode == MGCP_CONN_LOOPBACK) {
+		LOGP(DLMGCP, LOGL_NOTICE,
+		     "endpoint:%x RTP-setup: Endpoint is in loopback mode, stopping here!\n",
+		     ENDPOINT_NUMBER(endp));
+		return 0;
+	}
+
+	/* Find the "sister" connection */
+	llist_for_each_entry(_conn, &endp->conns, entry) {
+		if (_conn->id != conn->conn->id) {
+			conn_src = &_conn->u.rtp;
+			break;
+		}
+	}
+
+	return cfg->setup_rtp_processing_cb(endp, &conn_dst->end,
+					    &conn_src->end);
 }
 
-static uint32_t generate_call_id(struct mgcp_config *cfg)
-{
-	int i;
-
-	/* use the call id */
-	++cfg->last_call_id;
-
-	/* handle wrap around */
-	if (cfg->last_call_id == CI_UNUSED)
-		++cfg->last_call_id;
-
-	/* callstack can only be of size number_of_endpoints */
-	/* verify that the call id is free, e.g. in case of overrun */
-	for (i = 1; i < cfg->trunk.number_endpoints; ++i)
-		if (cfg->trunk.endpoints[i].ci == cfg->last_call_id)
-			return generate_call_id(cfg);
-
-	return cfg->last_call_id;
-}
-
-/*
- * array of function pointers for handling various
+/* array of function pointers for handling various
  * messages. In the future this might be binary sorted
- * for performance reasons.
- */
-static const struct mgcp_request mgcp_requests [] = {
+ * for performance reasons. */
+static const struct mgcp_request mgcp_requests[] = {
 	MGCP_REQUEST("AUEP", handle_audit_endpoint, "AuditEndpoint")
-	MGCP_REQUEST("CRCX", handle_create_con, "CreateConnection")
-	MGCP_REQUEST("DLCX", handle_delete_con, "DeleteConnection")
-	MGCP_REQUEST("MDCX", handle_modify_con, "ModifiyConnection")
-	MGCP_REQUEST("RQNT", handle_noti_req, "NotificationRequest")
+	    MGCP_REQUEST("CRCX", handle_create_con, "CreateConnection")
+	    MGCP_REQUEST("DLCX", handle_delete_con, "DeleteConnection")
+	    MGCP_REQUEST("MDCX", handle_modify_con, "ModifiyConnection")
+	    MGCP_REQUEST("RQNT", handle_noti_req, "NotificationRequest")
 
-	/* SPEC extension */
-	MGCP_REQUEST("RSIP", handle_rsip, "ReSetInProgress")
+	    /* SPEC extension */
+	    MGCP_REQUEST("RSIP", handle_rsip, "ReSetInProgress")
 };
 
+/* Helper function to allocate some memory for responses and retransmissions */
 static struct msgb *mgcp_msgb_alloc(void)
 {
 	struct msgb *msg;
 	msg = msgb_alloc_headroom(4096, 128, "MGCP msg");
 	if (!msg)
-	    LOGP(DLMGCP, LOGL_ERROR, "Failed to msgb for MGCP data.\n");
+		LOGP(DLMGCP, LOGL_ERROR, "Failed to msgb for MGCP data.\n");
 
 	return msg;
 }
 
+/* Helper function for do_retransmission() and create_resp() */
 static struct msgb *do_retransmission(const struct mgcp_endpoint *endp)
 {
 	struct msgb *msg = mgcp_msgb_alloc();
@@ -172,7 +124,7 @@
 
 	msg->l2h = msgb_put(msg, strlen(endp->last_response));
 	memcpy(msg->l2h, endp->last_response, msgb_l2len(msg));
-	display_mgcp_message(msg->l2h, msgb_l2len(msg), "Retransmitted response");
+	mgcp_disp_msg(msg->l2h, msgb_l2len(msg), "Retransmitted response");
 	return msg;
 }
 
@@ -188,8 +140,8 @@
 	if (!res)
 		return NULL;
 
-	len = snprintf((char *) res->data, 2048, "%d %s%s%s\r\n%s",
-			code, trans, txt, param ? param : "", sdp ? sdp : "");
+	len = snprintf((char *)res->data, 2048, "%d %s%s%s\r\n%s",
+		       code, trans, txt, param ? param : "", sdp ? sdp : "");
 	if (len < 0) {
 		LOGP(DLMGCP, LOGL_ERROR, "Failed to sprintf MGCP response.\n");
 		msgb_free(res);
@@ -198,7 +150,7 @@
 
 	res->l2h = msgb_put(res, len);
 	LOGP(DLMGCP, LOGL_DEBUG, "Generated response: code=%d\n", code);
-	display_mgcp_message(res->l2h, msgb_l2len(res), "Generated response");
+	mgcp_disp_msg(res->l2h, msgb_l2len(res), "Generated response");
 
 	/*
 	 * Remember the last transmission per endpoint.
@@ -209,33 +161,37 @@
 		talloc_free(endp->last_trans);
 		endp->last_trans = talloc_strdup(tcfg->endpoints, trans);
 		endp->last_response = talloc_strndup(tcfg->endpoints,
-						(const char *) res->l2h,
-						msgb_l2len(res));
+						     (const char *)res->l2h,
+						     msgb_l2len(res));
 	}
 
 	return res;
 }
 
 static struct msgb *create_ok_resp_with_param(struct mgcp_endpoint *endp,
-					int code, const char *msg,
-					const char *trans, const char *param)
+					      int code, const char *msg,
+					      const char *trans,
+					      const char *param)
 {
 	return create_resp(endp, code, " OK", msg, trans, param, NULL);
 }
 
 static struct msgb *create_ok_response(struct mgcp_endpoint *endp,
-					int code, const char *msg, const char *trans)
+				       int code, const char *msg,
+				       const char *trans)
 {
 	return create_ok_resp_with_param(endp, code, msg, trans, NULL);
 }
 
 static struct msgb *create_err_response(struct mgcp_endpoint *endp,
-					int code, const char *msg, const char *trans)
+					int code, const char *msg,
+					const char *trans)
 {
 	return create_resp(endp, code, " FAIL", msg, trans, NULL, NULL);
 }
 
 static int write_response_sdp(struct mgcp_endpoint *endp,
+			      struct mgcp_conn_rtp *conn,
 			      char *sdp_record, size_t size, const char *addr)
 {
 	const char *fmtp_extra;
@@ -244,16 +200,18 @@
 	int len;
 	int nchars;
 
+	if (!conn)
+		return -1;
+
 	endp->cfg->get_net_downlink_format_cb(endp, &payload_type,
-					      &audio_name, &fmtp_extra);
+					      &audio_name, &fmtp_extra, conn);
 
 	len = snprintf(sdp_record, size,
-			"v=0\r\n"
-			"o=- %u 23 IN IP4 %s\r\n"
-			"s=-\r\n"
-			"c=IN IP4 %s\r\n"
-			"t=0 0\r\n",
-			endp->ci, addr, addr);
+		       "v=0\r\n"
+		       "o=- %u 23 IN IP4 %s\r\n"
+		       "s=-\r\n"
+		       "c=IN IP4 %s\r\n"
+		       "t=0 0\r\n", conn->conn->id, addr, addr);
 
 	if (len < 0 || len >= size)
 		goto buffer_too_small;
@@ -261,7 +219,7 @@
 	if (payload_type >= 0) {
 		nchars = snprintf(sdp_record + len, size - len,
 				  "m=audio %d RTP/AVP %d\r\n",
-				  endp->net_end.local_port, payload_type);
+				  conn->end.local_port, payload_type);
 		if (nchars < 0 || nchars >= size - len)
 			goto buffer_too_small;
 
@@ -288,10 +246,10 @@
 			len += nchars;
 		}
 	}
-	if (endp->bts_end.packet_duration_ms > 0 && endp->tcfg->audio_send_ptime) {
+	if (conn->end.packet_duration_ms > 0 && endp->tcfg->audio_send_ptime) {
 		nchars = snprintf(sdp_record + len, size - len,
-				  "a=ptime:%d\r\n",
-				  endp->bts_end.packet_duration_ms);
+				  "a=ptime:%u\r\n",
+				  conn->end.packet_duration_ms);
 		if (nchars < 0 || nchars >= size - len)
 			goto buffer_too_small;
 
@@ -306,8 +264,11 @@
 	return -1;
 }
 
+/* Format MGCP response string (with SDP attached) */
 static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
-					     const char *msg, const char *trans_id)
+					     struct mgcp_conn_rtp *conn,
+					     const char *msg,
+					     const char *trans_id)
 {
 	const char *addr = endp->cfg->local_ip;
 	char sdp_record[4096];
@@ -318,19 +279,19 @@
 	if (!addr)
 		addr = mgcp_net_src_addr(endp);
 
-	if (endp->osmux.state == OSMUX_STATE_NEGOTIATING) {
-		sprintf(osmux_extension, "\nX-Osmux: %u", endp->osmux.cid);
-		endp->osmux.state = OSMUX_STATE_ACTIVATING;
+	if (conn->osmux.state == OSMUX_STATE_NEGOTIATING) {
+		sprintf(osmux_extension, "\nX-Osmux: %u", conn->osmux.cid);
+		conn->osmux.state = OSMUX_STATE_ACTIVATING;
 	} else {
 		osmux_extension[0] = '\0';
 	}
 
 	len = snprintf(sdp_record, sizeof(sdp_record),
-		       "I: %u%s\n\n", endp->ci, osmux_extension);
+		       "I: %u%s\n\n", conn->conn->id, osmux_extension);
 	if (len < 0)
 		return NULL;
 
-	nchars = write_response_sdp(endp, sdp_record + len,
+	nchars = write_response_sdp(endp, conn, sdp_record + len,
 				    sizeof(sdp_record) - len - 1, addr);
 	if (nchars < 0)
 		return NULL;
@@ -342,19 +303,19 @@
 	return create_resp(endp, 200, " OK", msg, trans_id, NULL, sdp_record);
 }
 
-static void send_dummy(struct mgcp_endpoint *endp)
+/* Send out dummy packet to keep the connection open, if the connection is an
+ * osmux connection, send the dummy packet via OSMUX */
+static void send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
 {
-	if (endp->osmux.state != OSMUX_STATE_DISABLED)
-		osmux_send_dummy(endp);
+	if (conn->osmux.state != OSMUX_STATE_DISABLED)
+		osmux_send_dummy(endp, conn);
 	else
-		mgcp_send_dummy(endp);
+		mgcp_send_dummy(endp, conn);
 }
 
-/*
- * handle incoming messages:
+/* handle incoming messages:
  *   - this can be a command (four letters, space, transaction id)
- *   - or a response (three numbers, space, transaction id)
- */
+ *   - or a response (three numbers, space, transaction id) */
 struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
 {
 	struct mgcp_parse_data pdata;
@@ -370,32 +331,33 @@
 	if (mgcp_msg_terminate_nul(msg))
 		return NULL;
 
-	display_mgcp_message(msg->l2h, msgb_l2len(msg), "Received message");
+	mgcp_disp_msg(msg->l2h, msgb_l2len(msg), "Received message");
 
-        /* attempt to treat it as a response */
-        if (sscanf((const char *)&msg->l2h[0], "%3d %*s", &code) == 1) {
+	/* attempt to treat it as a response */
+	if (sscanf((const char *)&msg->l2h[0], "%3d %*s", &code) == 1) {
 		LOGP(DLMGCP, LOGL_DEBUG, "Response: Code: %d\n", code);
 		return NULL;
 	}
 
 	msg->l3h = &msg->l2h[4];
 
-
 	/*
 	 * Check for a duplicate message and respond.
 	 */
 	memset(&pdata, 0, sizeof(pdata));
 	pdata.cfg = cfg;
-	data = strline_r((char *) msg->l3h, &pdata.save);
-	pdata.found = mgcp_analyze_header(&pdata, data);
+	data = mgcp_strline((char *)msg->l3h, &pdata.save);
+	pdata.found = mgcp_parse_header(&pdata, data);
 	if (pdata.endp && pdata.trans
-			&& pdata.endp->last_trans
-			&& strcmp(pdata.endp->last_trans, pdata.trans) == 0) {
+	    && pdata.endp->last_trans
+	    && strcmp(pdata.endp->last_trans, pdata.trans) == 0) {
 		return do_retransmission(pdata.endp);
 	}
 
 	for (i = 0; i < ARRAY_SIZE(mgcp_requests); ++i) {
-		if (strncmp(mgcp_requests[i].name, (const char *) &msg->l2h[0], 4) == 0) {
+		if (strncmp
+		    (mgcp_requests[i].name, (const char *)&msg->l2h[0],
+		     4) == 0) {
 			handled = 1;
 			resp = mgcp_requests[i].handle_request(&pdata);
 			break;
@@ -403,201 +365,40 @@
 	}
 
 	if (!handled)
-		LOGP(DLMGCP, LOGL_NOTICE, "MSG with type: '%.4s' not handled\n", &msg->l2h[0]);
+		LOGP(DLMGCP, LOGL_NOTICE, "MSG with type: '%.4s' not handled\n",
+		     &msg->l2h[0]);
 
 	return resp;
 }
 
-/**
- * We have a null terminated string with the endpoint name here. We only
- * support two kinds. Simple ones as seen on the BSC level and the ones
- * seen on the trunk side.
- */
-static struct mgcp_endpoint *find_e1_endpoint(struct mgcp_config *cfg,
-					     const char *mgcp)
-{
-	char *rest = NULL;
-	struct mgcp_trunk_config *tcfg;
-	int trunk, endp;
-
-	trunk = strtoul(mgcp + 6, &rest, 10);
-	if (rest == NULL || rest[0] != '/' || trunk < 1) {
-		LOGP(DLMGCP, LOGL_ERROR, "Wrong trunk name '%s'\n", mgcp);
-		return NULL;
-	}
-
-	endp = strtoul(rest + 1, &rest, 10);
-	if (rest == NULL || rest[0] != '@') {
-		LOGP(DLMGCP, LOGL_ERROR, "Wrong endpoint name '%s'\n", mgcp);
-		return NULL;
-	}
-
-	/* signalling is on timeslot 1 */
-	if (endp == 1)
-		return NULL;
-
-	tcfg = mgcp_trunk_num(cfg, trunk);
-	if (!tcfg) {
-		LOGP(DLMGCP, LOGL_ERROR, "The trunk %d is not declared.\n", trunk);
-		return NULL;
-	}
-
-	if (!tcfg->endpoints) {
-		LOGP(DLMGCP, LOGL_ERROR, "Endpoints of trunk %d not allocated.\n", trunk);
-		return NULL;
-	}
-
-	if (endp < 1 || endp >= tcfg->number_endpoints) {
-		LOGP(DLMGCP, LOGL_ERROR, "Failed to find endpoint '%s'\n", mgcp);
-		return NULL;
-	}
-
-	return &tcfg->endpoints[endp];
-}
-
-static struct mgcp_endpoint *find_endpoint(struct mgcp_config *cfg, const char *mgcp)
-{
-	char *endptr = NULL;
-	unsigned int gw = INT_MAX;
-
-	if (strncmp(mgcp, "ds/e1", 5) == 0)
-		return find_e1_endpoint(cfg, mgcp);
-
-	gw = strtoul(mgcp, &endptr, 16);
-	if (gw > 0 && gw < cfg->trunk.number_endpoints && endptr[0] == '@')
-		return &cfg->trunk.endpoints[gw];
-
-	LOGP(DLMGCP, LOGL_ERROR, "Not able to find the endpoint: '%s'\n", mgcp);
-	return NULL;
-}
-
-/**
- * @returns 0 when the status line was complete and transaction_id and
- * endp out parameters are set.
- */
-static int mgcp_analyze_header(struct mgcp_parse_data *pdata, char *data)
-{
-	int i = 0;
-	char *elem, *save = NULL;
-
-	OSMO_ASSERT(data);
-	pdata->trans = "000000";
-
-	for (elem = strtok_r(data, " ", &save); elem;
-	     elem = strtok_r(NULL, " ", &save)) {
-		switch (i) {
-		case 0:
-			pdata->trans = elem;
-			break;
-		case 1:
-			pdata->endp = find_endpoint(pdata->cfg, elem);
-			if (!pdata->endp) {
-				LOGP(DLMGCP, LOGL_ERROR,
-				     "Unable to find Endpoint `%s'\n", elem);
-				return -1;
-			}
-			break;
-		case 2:
-			if (strcmp("MGCP", elem)) {
-				LOGP(DLMGCP, LOGL_ERROR,
-				     "MGCP header parsing error\n");
-				return -1;
-			}
-			break;
-		case 3:
-			if (strcmp("1.0", elem)) {
-				LOGP(DLMGCP, LOGL_ERROR, "MGCP version `%s' "
-					"not supported\n", elem);
-				return -1;
-			}
-			break;
-		}
-		i++;
-	}
-
-	if (i != 4) {
-		LOGP(DLMGCP, LOGL_ERROR, "MGCP status line too short.\n");
-		pdata->trans = "000000";
-		pdata->endp = NULL;
-		return -1;
-	}
-
-	return 0;
-}
-
-static int verify_call_id(const struct mgcp_endpoint *endp,
-			  const char *callid)
-{
-	if (strcmp(endp->callid, callid) != 0) {
-		LOGP(DLMGCP, LOGL_ERROR, "CallIDs does not match on 0x%x. '%s' != '%s'\n",
-			ENDPOINT_NUMBER(endp), endp->callid, callid);
-		return -1;
-	}
-
-	return 0;
-}
-
-static int verify_ci(const struct mgcp_endpoint *endp,
-		     const char *_ci)
-{
-	uint32_t ci = strtoul(_ci, NULL, 10);
-
-	if (ci != endp->ci) {
-		LOGP(DLMGCP, LOGL_ERROR, "ConnectionIdentifiers do not match on 0x%x. %u != %s\n",
-			ENDPOINT_NUMBER(endp), endp->ci, _ci);
-		return -1;
-	}
-
-	return 0;
-}
-
+/* AUEP command handler, processes the received command */
 static struct msgb *handle_audit_endpoint(struct mgcp_parse_data *p)
 {
-	if (p->found != 0)
+	LOGP(DLMGCP, LOGL_NOTICE, "AUEP: auditing endpoint ...\n");
+
+	if (p->found != 0) {
+		LOGP(DLMGCP, LOGL_ERROR,
+		     "AUEP: failed to find the endpoint.\n");
 		return create_err_response(NULL, 500, "AUEP", p->trans);
-	else
+	} else
 		return create_ok_response(p->endp, 200, "AUEP", p->trans);
 }
 
-static int parse_conn_mode(const char *msg, struct mgcp_endpoint *endp)
-{
-	int ret = 0;
-	if (strcmp(msg, "recvonly") == 0)
-		endp->conn_mode = MGCP_CONN_RECV_ONLY;
-	else if (strcmp(msg, "sendrecv") == 0)
-		endp->conn_mode = MGCP_CONN_RECV_SEND;
-	else if (strcmp(msg, "sendonly") == 0)
-		endp->conn_mode = MGCP_CONN_SEND_ONLY;
-	else if (strcmp(msg, "loopback") == 0)
-		endp->conn_mode = MGCP_CONN_LOOPBACK;
-	else {
-		LOGP(DLMGCP, LOGL_ERROR, "Unknown connection mode: '%s'\n", msg);
-		ret = -1;
-	}
-
-	endp->net_end.output_enabled =
-		endp->conn_mode & MGCP_CONN_SEND_ONLY ? 1 : 0;
-	endp->bts_end.output_enabled =
-		endp->conn_mode & MGCP_CONN_RECV_ONLY ? 1 : 0;
-
-	LOGP(DLMGCP, LOGL_DEBUG, "endpoint %x connection mode '%s' %d output_enabled net %d bts %d\n",
-	     ENDPOINT_NUMBER(endp),
-	     msg, endp->conn_mode, endp->net_end.output_enabled,
-	     endp->bts_end.output_enabled);
-
-	return ret;
-}
-
-static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_rtp_end *end,
-			 struct mgcp_port_range *range,
-			 int (*alloc)(struct mgcp_endpoint *endp, int port))
+/* Try to find a free port by attemting to bind on it. Also handle the
+ * counter that points on the next free port. Since we have a pointer
+ * to the next free port, binding should work on the first attemt,
+ * neverless, try at least the next 200 ports before giving up */
+static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
 {
 	int i;
+	struct mgcp_rtp_end *end;
+	struct mgcp_port_range *range;
 
-	if (range->mode == PORT_ALLOC_STATIC) {
-		end->local_alloc = PORT_ALLOC_STATIC;
-		return 0;
-	}
+	OSMO_ASSERT(conn);
+	end = &conn->end;
+	OSMO_ASSERT(end);
+
+	range = &endp->cfg->net_ports;
 
 	/* attempt to find a port */
 	for (i = 0; i < 200; ++i) {
@@ -606,60 +407,23 @@
 		if (range->last_port >= range->range_end)
 			range->last_port = range->range_start;
 
-		rc = alloc(endp, range->last_port);
+		rc = mgcp_bind_net_rtp_port(endp, range->last_port, conn);
 
 		range->last_port += 2;
 		if (rc == 0) {
-			end->local_alloc = PORT_ALLOC_DYNAMIC;
 			return 0;
 		}
 
 	}
 
-	LOGP(DLMGCP, LOGL_ERROR, "Allocating a RTP/RTCP port failed 200 times 0x%x.\n",
+	LOGP(DLMGCP, LOGL_ERROR,
+	     "Allocating a RTP/RTCP port failed 200 times 0x%x.\n",
 	     ENDPOINT_NUMBER(endp));
 	return -1;
 }
 
-static int allocate_ports(struct mgcp_endpoint *endp)
-{
-	if (allocate_port(endp, &endp->net_end, &endp->cfg->net_ports,
-			  mgcp_bind_net_rtp_port) != 0)
-		return -1;
-
-	if (allocate_port(endp, &endp->bts_end, &endp->cfg->bts_ports,
-			  mgcp_bind_bts_rtp_port) != 0) {
-		mgcp_rtp_end_reset(&endp->net_end);
-		return -1;
-	}
-
-	if (endp->cfg->transcoder_ip && endp->tcfg->trunk_type == MGCP_TRUNK_VIRTUAL) {
-		if (allocate_port(endp, &endp->trans_net,
-				  &endp->cfg->transcoder_ports,
-				  mgcp_bind_trans_net_rtp_port) != 0) {
-			mgcp_rtp_end_reset(&endp->net_end);
-			mgcp_rtp_end_reset(&endp->bts_end);
-			return -1;
-		}
-
-		if (allocate_port(endp, &endp->trans_bts,
-				  &endp->cfg->transcoder_ports,
-				  mgcp_bind_trans_bts_rtp_port) != 0) {
-			mgcp_rtp_end_reset(&endp->net_end);
-			mgcp_rtp_end_reset(&endp->bts_end);
-			mgcp_rtp_end_reset(&endp->trans_net);
-			return -1;
-		}
-
-		/* remember that we have set up transcoding */
-		endp->type = MGCP_RTP_TRANSCODED;
-	}
-
-	return 0;
-}
-
 /* Set the LCO from a string (see RFC 3435).
- * The string is stored in the 'string' field. A NULL string is handled excatly
+ * The string is stored in the 'string' field. A NULL string is handled excatlyy
  * like an empty string, the 'string' field is never NULL after this function
  * has been called. */
 static void set_local_cx_options(void *ctx, struct mgcp_lco *lco,
@@ -682,6 +446,10 @@
 	a_opt = strstr(lco->string, "a:");
 	if (a_opt && sscanf(a_opt, "a:%8[^,]", codec) == 1)
 		lco->codec = talloc_strdup(ctx, codec);
+
+	LOGP(DLMGCP, LOGL_DEBUG,
+	     "local CX options: lco->pkt_period_max: %i, lco->codec: %s\n",
+	     lco->pkt_period_max, lco->codec);
 }
 
 void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
@@ -711,28 +479,13 @@
 		f = rtp->frames_per_packet;
 	else if (rtp->packet_duration_ms && rtp->codec.frame_duration_num) {
 		int den = 1000 * rtp->codec.frame_duration_num;
-		f = (rtp->packet_duration_ms * rtp->codec.frame_duration_den + den/2)
-			/ den;
+		f = (rtp->packet_duration_ms * rtp->codec.frame_duration_den +
+		     den / 2)
+		    / den;
 	}
 
-	return rtp->codec.rate * f * rtp->codec.frame_duration_num / rtp->codec.frame_duration_den;
-}
-
-static int mgcp_parse_osmux_cid(const char *line)
-{
-	int osmux_cid;
-
-	if (sscanf(line + 2, "Osmux: %u", &osmux_cid) != 1)
-		return -1;
-
-	if (osmux_cid > OSMUX_CID_MAX) {
-		LOGP(DLMGCP, LOGL_ERROR, "Osmux ID too large: %u > %u\n",
-		     osmux_cid, OSMUX_CID_MAX);
-		return -1;
-	}
-	LOGP(DLMGCP, LOGL_DEBUG, "bsc-nat offered Osmux CID %u\n", osmux_cid);
-
-	return osmux_cid;
+	return rtp->codec.rate * f * rtp->codec.frame_duration_num /
+	    rtp->codec.frame_duration_den;
 }
 
 static int mgcp_osmux_setup(struct mgcp_endpoint *endp, const char *line)
@@ -748,6 +501,7 @@
 	return mgcp_parse_osmux_cid(line);
 }
 
+/* CRCX command handler, processes the received command */
 static struct msgb *handle_create_con(struct mgcp_parse_data *p)
 {
 	struct mgcp_trunk_config *tcfg;
@@ -756,9 +510,15 @@
 
 	const char *local_options = NULL;
 	const char *callid = NULL;
+	const char *ci = NULL;
 	const char *mode = NULL;
 	char *line;
 	int have_sdp = 0, osmux_cid = -1;
+	struct mgcp_conn_rtp *conn = NULL;
+	uint32_t conn_id;
+	char conn_name[512];
+
+	LOGP(DLMGCP, LOGL_NOTICE, "CRCX: creating new connection ...\n");
 
 	if (p->found != 0)
 		return create_err_response(NULL, 510, "CRCX", p->trans);
@@ -770,30 +530,32 @@
 
 		switch (line[0]) {
 		case 'L':
-			local_options = (const char *) line + 3;
+			local_options = (const char *)line + 3;
 			break;
 		case 'C':
-			callid = (const char *) line + 3;
+			callid = (const char *)line + 3;
+			break;
+		case 'I':
+			ci = (const char *)line + 3;
 			break;
 		case 'M':
-			mode = (const char *) line + 3;
+			mode = (const char *)line + 3;
 			break;
 		case 'X':
-			/* Osmux is not enabled in this bsc, ignore it so the
-			 * bsc-nat knows that we don't want to use Osmux.
-			 */
+			/* If osmoux is disabled, just skip setting it up */
 			if (!p->endp->cfg->osmux)
 				break;
-
-			if (strncmp("Osmux: ", line + 2, strlen("Osmux: ")) == 0)
+			if (strncmp("Osmux: ", line + 2, strlen("Osmux: ")) ==
+			    0)
 				osmux_cid = mgcp_osmux_setup(endp, line);
 			break;
 		case '\0':
 			have_sdp = 1;
 			goto mgcp_header_done;
 		default:
-			LOGP(DLMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
-				*line, *line, ENDPOINT_NUMBER(endp));
+			LOGP(DLMGCP, LOGL_NOTICE,
+			     "CRCX: endpoint:%x unhandled option: '%c'/%d\n",
+			     ENDPOINT_NUMBER(endp), *line, *line);
 			break;
 		}
 	}
@@ -801,103 +563,165 @@
 mgcp_header_done:
 	tcfg = p->endp->tcfg;
 
-	/* Check required data */
-	if (!callid || !mode) {
-		LOGP(DLMGCP, LOGL_ERROR, "Missing callid and mode in CRCX on 0x%x\n",
+	/* Check parameters */
+	if (!callid) {
+		LOGP(DLMGCP, LOGL_ERROR,
+		     "CRCX: endpoint:%x insufficient parameters, missing callid\n",
 		     ENDPOINT_NUMBER(endp));
 		return create_err_response(endp, 400, "CRCX", p->trans);
 	}
 
-	if (endp->allocated) {
+	if (!mode) {
+		LOGP(DLMGCP, LOGL_ERROR,
+		     "CRCX: endpoint:%x insufficient parameters, missing mode\n",
+		     ENDPOINT_NUMBER(endp));
+		return create_err_response(endp, 400, "CRCX", p->trans);
+	}
+
+	if (!ci) {
+		LOGP(DLMGCP, LOGL_ERROR,
+		     "CRCX: endpoint:%x insufficient parameters, missing connection id\n",
+		     ENDPOINT_NUMBER(endp));
+		return create_err_response(endp, 400, "CRCX", p->trans);
+	}
+
+	/* Check if we are able to accept the creation of another connection */
+	if (llist_count(&endp->conns) >= endp->type->max_conns) {
+		LOGP(DLMGCP, LOGL_ERROR,
+		     "CRCX: endpoint:%x endpoint full, max. %i connections allowed!\n",
+		     endp->type->max_conns, ENDPOINT_NUMBER(endp));
 		if (tcfg->force_realloc) {
-			LOGP(DLMGCP, LOGL_NOTICE, "Endpoint 0x%x already allocated. Forcing realloc.\n",
-			    ENDPOINT_NUMBER(endp));
-			mgcp_release_endp(endp);
-			if (p->cfg->realloc_cb)
-				p->cfg->realloc_cb(tcfg, ENDPOINT_NUMBER(endp));
+			/* There is no more room for a connection, make some
+			 * room by blindly tossing the oldest of the two two
+			 * connections */
+			mgcp_conn_free_oldest(endp);
 		} else {
-			LOGP(DLMGCP, LOGL_ERROR, "Endpoint is already used. 0x%x\n",
-			     ENDPOINT_NUMBER(endp));
+			/* There is no more room for a connection, leave
+			 * everything as it is and return with an error */
 			return create_err_response(endp, 400, "CRCX", p->trans);
 		}
 	}
 
-	/* copy some parameters */
+	/* Check if this endpoint already serves a call, if so, check if the
+	 * callids match up so that we are sure that this is our call */
+	if (endp->callid && mgcp_verify_call_id(endp, callid)) {
+		LOGP(DLMGCP, LOGL_ERROR,
+		     "CRCX: endpoint:%x allready seized by other call (%s)\n",
+		     ENDPOINT_NUMBER(endp), endp->callid);
+		if (tcfg->force_realloc)
+			/* This is not our call, toss everything by releasing
+			 * the entire endpoint. (rude!) */
+			mgcp_release_endp(endp);
+		else {
+			/* This is not our call, leave everything as it is and
+			 * return with an error. */
+			return create_err_response(endp, 400, "CRCX", p->trans);
+		}
+	}
+
+	/* Set the callid, creation of another connection will only be possible
+	 * when the callid matches up. (Connections are distinuished by their
+	 * connection ids) */
 	endp->callid = talloc_strdup(tcfg->endpoints, callid);
 
+	/* Extract audio codec information */
 	set_local_cx_options(endp->tcfg->endpoints, &endp->local_options,
 			     local_options);
 
-	if (parse_conn_mode(mode, endp) != 0) {
-		    error_code = 517;
-		    goto error2;
+	if (mgcp_parse_ci(&conn_id, ci)) {
+		LOGP(DLMGCP, LOGL_ERROR,
+		     "CRCX: endpoint:%x insufficient parameters, missing ci (connectionIdentifier)\n",
+		     ENDPOINT_NUMBER(endp));
+		return create_err_response(endp, 400, "CRCX", p->trans);
 	}
 
-	/* initialize */
-	endp->net_end.rtp_port = endp->net_end.rtcp_port = endp->bts_end.rtp_port = endp->bts_end.rtcp_port = 0;
-	mgcp_rtp_end_config(endp, 0, &endp->net_end);
-	mgcp_rtp_end_config(endp, 0, &endp->bts_end);
+	/* Only accept another connection when the connection ID is different. */
+	if (mgcp_conn_get_rtp(endp, conn_id)) {
+		LOGP(DLMGCP, LOGL_ERROR,
+		     "CRCX: endpoint:%x there is already a connection with id %u present!\n",
+		     conn_id, ENDPOINT_NUMBER(endp));
+		if (tcfg->force_realloc) {
+			/* Ignore the existing connection by just freeing it */
+			mgcp_conn_free(endp, conn_id);
+		} else {
+			/* There is already a connection with that ID present,
+			 * leave everything as it is and return with an error. */
+			return create_err_response(endp, 400, "CRCX", p->trans);
+		}
+	}
 
-	/* set to zero until we get the info */
-	memset(&endp->net_end.addr, 0, sizeof(endp->net_end.addr));
-
-	/* bind to the port now */
-	if (allocate_ports(endp) != 0)
+	snprintf(conn_name, sizeof(conn_name), "%s-%u", callid, conn_id);
+	mgcp_conn_alloc(NULL, endp, conn_id, MGCP_CONN_TYPE_RTP,
+			conn_name);
+	conn = mgcp_conn_get_rtp(endp, conn_id);
+	if (!conn) {
+		LOGP(DLMGCP, LOGL_ERROR,
+		     "CRCX: endpoint:%x unable to allocate RTP connection\n",
+		     ENDPOINT_NUMBER(endp));
 		goto error2;
 
-	/* assign a local call identifier or fail */
-	endp->ci = generate_call_id(p->cfg);
-	if (endp->ci == CI_UNUSED)
+	}
+
+	if (mgcp_parse_conn_mode(mode, endp, conn->conn) != 0) {
+		error_code = 517;
 		goto error2;
+	}
+
+	mgcp_rtp_end_config(endp, 0, &conn->end);
+
+	if (allocate_port(endp, conn) != 0) {
+		goto error2;
+	}
 
 	/* Annotate Osmux circuit ID and set it to negotiating state until this
-	 * is fully set up from the dummy load.
-	 */
-	endp->osmux.state = OSMUX_STATE_DISABLED;
+	 * is fully set up from the dummy load. */
+	conn->osmux.state = OSMUX_STATE_DISABLED;
 	if (osmux_cid >= 0) {
-		endp->osmux.cid = osmux_cid;
-		endp->osmux.state = OSMUX_STATE_NEGOTIATING;
+		conn->osmux.cid = osmux_cid;
+		conn->osmux.state = OSMUX_STATE_NEGOTIATING;
 	} else if (endp->cfg->osmux == OSMUX_USAGE_ONLY) {
 		LOGP(DLMGCP, LOGL_ERROR,
-			"Osmux only and no osmux offered on 0x%x\n", ENDPOINT_NUMBER(endp));
+		     "CRCX: endpoint:%x osmux only and no osmux offered\n",
+		     ENDPOINT_NUMBER(endp));
 		goto error2;
 	}
 
-	endp->allocated = 1;
-
 	/* set up RTP media parameters */
-	mgcp_set_audio_info(p->cfg, &endp->bts_end.codec, tcfg->audio_payload, tcfg->audio_name);
-	endp->bts_end.fmtp_extra = talloc_strdup(tcfg->endpoints,
-						tcfg->audio_fmtp_extra);
 	if (have_sdp)
-		mgcp_parse_sdp_data(endp, &endp->net_end, p);
+		mgcp_parse_sdp_data(endp, &conn->end, p);
 	else if (endp->local_options.codec)
-		mgcp_set_audio_info(p->cfg, &endp->net_end.codec,
-			       PTYPE_UNDEFINED, endp->local_options.codec);
+		mgcp_set_audio_info(p->cfg, &conn->end.codec,
+				    PTYPE_UNDEFINED, endp->local_options.codec);
+	conn->end.fmtp_extra = talloc_strdup(tcfg->endpoints,
+					     tcfg->audio_fmtp_extra);
 
-	if (p->cfg->bts_force_ptime) {
-		endp->bts_end.packet_duration_ms = p->cfg->bts_force_ptime;
-		endp->bts_end.force_output_ptime = 1;
+	if (p->cfg->force_ptime) {
+		conn->end.packet_duration_ms = p->cfg->force_ptime;
+		conn->end.force_output_ptime = 1;
 	}
 
-	if (setup_rtp_processing(endp) != 0)
+	if (setup_rtp_processing(endp, conn) != 0) {
+		LOGP(DLMGCP, LOGL_ERROR,
+		     "CRCX: endpoint:%x could not start RTP processing!\n",
+		     ENDPOINT_NUMBER(endp));
 		goto error2;
+	}
 
 	/* policy CB */
 	if (p->cfg->policy_cb) {
 		int rc;
 		rc = p->cfg->policy_cb(tcfg, ENDPOINT_NUMBER(endp),
-				MGCP_ENDP_CRCX, p->trans);
+				       MGCP_ENDP_CRCX, p->trans);
 		switch (rc) {
 		case MGCP_POLICY_REJECT:
-			LOGP(DLMGCP, LOGL_NOTICE, "CRCX rejected by policy on 0x%x\n",
+			LOGP(DLMGCP, LOGL_NOTICE,
+			     "CRCX: endpoint:%x CRCX rejected by policy\n",
 			     ENDPOINT_NUMBER(endp));
 			mgcp_release_endp(endp);
 			return create_err_response(endp, 400, "CRCX", p->trans);
 			break;
 		case MGCP_POLICY_DEFER:
 			/* stop processing */
-			create_transcoder(endp);
 			return NULL;
 			break;
 		case MGCP_POLICY_CONT:
@@ -906,24 +730,30 @@
 		}
 	}
 
-	LOGP(DLMGCP, LOGL_DEBUG, "Creating endpoint on: 0x%x CI: %u port: %u/%u\n",
-		ENDPOINT_NUMBER(endp), endp->ci,
-		endp->net_end.local_port, endp->bts_end.local_port);
+	LOGP(DLMGCP, LOGL_DEBUG,
+	     "CRCX: endpoint:%x Creating connection: CI: %u port: %u\n",
+	     ENDPOINT_NUMBER(endp), conn->conn->id, conn->end.local_port);
 	if (p->cfg->change_cb)
 		p->cfg->change_cb(tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX);
 
-	if (endp->conn_mode & MGCP_CONN_RECV_ONLY && tcfg->keepalive_interval != 0) {
-		send_dummy(endp);
+	if (conn->conn->mode & MGCP_CONN_RECV_ONLY
+	    && tcfg->keepalive_interval != 0) {
+		send_dummy(endp, conn);
 	}
 
-	create_transcoder(endp);
-	return create_response_with_sdp(endp, "CRCX", p->trans);
+	LOGP(DLMGCP, LOGL_NOTICE,
+	     "CRCX: endpoint:%x connection successfully created\n",
+	     ENDPOINT_NUMBER(endp));
+	return create_response_with_sdp(endp, conn, "CRCX", p->trans);
 error2:
 	mgcp_release_endp(endp);
-	LOGP(DLMGCP, LOGL_NOTICE, "Resource error on 0x%x\n", ENDPOINT_NUMBER(endp));
+	LOGP(DLMGCP, LOGL_NOTICE,
+	     "CRCX: endpoint:%x unable to create connection resource error\n",
+	     ENDPOINT_NUMBER(endp));
 	return create_err_response(endp, error_code, "CRCX", p->trans);
 }
 
+/* MDCX command handler, processes the received command */
 static struct msgb *handle_modify_con(struct mgcp_parse_data *p)
 {
 	struct mgcp_endpoint *endp = p->endp;
@@ -931,14 +761,21 @@
 	int silent = 0;
 	int have_sdp = 0;
 	char *line;
+	const char *ci = NULL;
 	const char *local_options = NULL;
+	const char *mode = NULL;
+	struct mgcp_conn_rtp *conn = NULL;
+	uint32_t conn_id;
+
+	LOGP(DLMGCP, LOGL_NOTICE, "MDCX: modifying existing connection ...\n");
 
 	if (p->found != 0)
 		return create_err_response(NULL, 510, "MDCX", p->trans);
 
-	if (endp->ci == CI_UNUSED) {
-		LOGP(DLMGCP, LOGL_ERROR, "Endpoint is not "
-			"holding a connection. 0x%x\n", ENDPOINT_NUMBER(endp));
+	if (llist_count(&endp->conns) <= 0) {
+		LOGP(DLMGCP, LOGL_ERROR,
+		     "MDCX: endpoint:%x endpoint is not holding a connection.\n",
+		     ENDPOINT_NUMBER(endp));
 		return create_err_response(endp, 400, "MDCX", p->trans);
 	}
 
@@ -947,62 +784,79 @@
 			continue;
 
 		switch (line[0]) {
-		case 'C': {
-			if (verify_call_id(endp, line + 3) != 0)
+		case 'C':
+			if (mgcp_verify_call_id(endp, line + 3) != 0)
 				goto error3;
 			break;
-		}
-		case 'I': {
-			if (verify_ci(endp, line + 3) != 0)
+		case 'I':
+			ci = (const char *)line + 3;
+			if (mgcp_verify_ci(endp, ci) != 0)
 				goto error3;
 			break;
-		}
 		case 'L':
-			local_options = (const char *) line + 3;
+			local_options = (const char *)line + 3;
 			break;
 		case 'M':
-			if (parse_conn_mode(line + 3, endp) != 0) {
-			    error_code = 517;
-			    goto error3;
-			}
-			endp->orig_mode = endp->conn_mode;
+			mode = (const char *)line + 3;
 			break;
 		case 'Z':
 			silent = strcmp("noanswer", line + 3) == 0;
 			break;
 		case '\0':
-			/* SDP file begins */
 			have_sdp = 1;
-			mgcp_parse_sdp_data(endp, &endp->net_end, p);
-			/* This will exhaust p->save, so the loop will
-			 * terminate next time.
-			 */
+			goto mgcp_header_done;
 			break;
 		default:
-			LOGP(DLMGCP, LOGL_NOTICE, "Unhandled MGCP option: '%c'/%d on 0x%x\n",
-				line[0], line[0], ENDPOINT_NUMBER(endp));
+			LOGP(DLMGCP, LOGL_NOTICE,
+			     "MDCX: endpoint:%x Unhandled MGCP option: '%c'/%d\n",
+			     ENDPOINT_NUMBER(endp), line[0], line[0]);
 			break;
 		}
 	}
 
+mgcp_header_done:
+	if (mgcp_parse_ci(&conn_id, ci)) {
+		LOGP(DLMGCP, LOGL_ERROR,
+		     "MDCX: endpoint:%x insufficient parameters, missing ci (connectionIdentifier)\n",
+		     ENDPOINT_NUMBER(endp));
+		return create_err_response(endp, 400, "MDCX", p->trans);
+	}
+
+	conn = mgcp_conn_get_rtp(endp, conn_id);
+	if (!conn)
+		return create_err_response(endp, 400, "MDCX", p->trans);
+
+	if (mode) {
+		if (mgcp_parse_conn_mode(mode, endp, conn->conn) != 0) {
+			error_code = 517;
+			goto error3;
+		}
+	} else
+			conn->conn->mode = conn->conn->mode_orig;
+
+	if (have_sdp)
+		mgcp_parse_sdp_data(endp, &conn->end, p);
+
 	set_local_cx_options(endp->tcfg->endpoints, &endp->local_options,
 			     local_options);
 
 	if (!have_sdp && endp->local_options.codec)
-		mgcp_set_audio_info(p->cfg, &endp->net_end.codec,
-			       PTYPE_UNDEFINED, endp->local_options.codec);
+		mgcp_set_audio_info(p->cfg, &conn->end.codec,
+				    PTYPE_UNDEFINED, endp->local_options.codec);
 
-	if (setup_rtp_processing(endp) != 0)
+	if (setup_rtp_processing(endp, conn) != 0)
 		goto error3;
 
+
 	/* policy CB */
 	if (p->cfg->policy_cb) {
 		int rc;
 		rc = p->cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
-						MGCP_ENDP_MDCX, p->trans);
+				       MGCP_ENDP_MDCX, p->trans);
 		switch (rc) {
 		case MGCP_POLICY_REJECT:
-			LOGP(DLMGCP, LOGL_NOTICE, "MDCX rejected by policy on 0x%x\n",
+			LOGP(DLMGCP, LOGL_NOTICE,
+			     "MDCX: endpoint:%x rejected by policy\n",
 			     ENDPOINT_NUMBER(endp));
 			if (silent)
 				goto out_silent;
@@ -1010,7 +864,8 @@
 			break;
 		case MGCP_POLICY_DEFER:
 			/* stop processing */
-			LOGP(DLMGCP, LOGL_DEBUG, "endp %x MDCX defer\n",
+			LOGP(DLMGCP, LOGL_DEBUG,
+			     "MDCX: endpoint:%x defered by policy\n",
 			     ENDPOINT_NUMBER(endp));
 			return NULL;
 			break;
@@ -1020,34 +875,37 @@
 		}
 	}
 
-	mgcp_rtp_end_config(endp, 1, &endp->net_end);
-	mgcp_rtp_end_config(endp, 1, &endp->bts_end);
+	mgcp_rtp_end_config(endp, 1, &conn->end);
 
 	/* modify */
-	LOGP(DLMGCP, LOGL_DEBUG, "Modified endpoint on: 0x%x Server: %s:%u\n",
-		ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
+	LOGP(DLMGCP, LOGL_DEBUG,
+	     "MDCX: endpoint:%x modified conn:%s\n",
+	     ENDPOINT_NUMBER(endp), mgcp_conn_dump(conn->conn));
 	if (p->cfg->change_cb)
-		p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX);
+		p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
+				  MGCP_ENDP_MDCX);
 
-	if (endp->conn_mode & MGCP_CONN_RECV_ONLY &&
+	if (conn->conn->mode & MGCP_CONN_RECV_ONLY &&
 	    endp->tcfg->keepalive_interval != 0)
-		send_dummy(endp);
+		send_dummy(endp, conn);
 
 	if (silent)
 		goto out_silent;
 
-	return create_response_with_sdp(endp, "MDCX", p->trans);
-
+	LOGP(DLMGCP, LOGL_NOTICE,
+	     "MDCX: endpoint:%x connection successfully modified\n",
+	     ENDPOINT_NUMBER(endp));
+	return create_response_with_sdp(endp, conn, "MDCX", p->trans);
 error3:
 	return create_err_response(endp, error_code, "MDCX", p->trans);
 
-
 out_silent:
-	LOGP(DLMGCP, LOGL_DEBUG, "endp %x Modify endpoint: silent exit\n",
+	LOGP(DLMGCP, LOGL_DEBUG, "MDCX: endpoint:%x silent exit\n",
 	     ENDPOINT_NUMBER(endp));
 	return NULL;
 }
 
+/* DLCX command handler, processes the received command */
 static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
 {
 	struct mgcp_endpoint *endp = p->endp;
@@ -1055,13 +913,21 @@
 	int silent = 0;
 	char *line;
 	char stats[1048];
+	const char *ci = NULL;
+	struct mgcp_conn_rtp *conn = NULL;
+	uint32_t conn_id;
+
+	LOGP(DLMGCP, LOGL_NOTICE,
+	     "DLCX: endpoint:%x deleting connection ...\n",
+	     ENDPOINT_NUMBER(endp));
 
 	if (p->found != 0)
 		return create_err_response(NULL, error_code, "DLCX", p->trans);
 
-	if (!p->endp->allocated) {
-		LOGP(DLMGCP, LOGL_ERROR, "Endpoint is not used. 0x%x\n",
-			ENDPOINT_NUMBER(endp));
+	if (llist_count(&endp->conns) <= 0) {
+		LOGP(DLMGCP, LOGL_ERROR,
+		     "DLCX: endpoint:%x endpoint is not holding a connection.\n",
+		     ENDPOINT_NUMBER(endp));
 		return create_err_response(endp, 400, "DLCX", p->trans);
 	}
 
@@ -1071,19 +937,21 @@
 
 		switch (line[0]) {
 		case 'C':
-			if (verify_call_id(endp, line + 3) != 0)
+			if (mgcp_verify_call_id(endp, line + 3) != 0)
 				goto error3;
 			break;
 		case 'I':
-			if (verify_ci(endp, line + 3) != 0)
+			ci = (const char *)line + 3;
+			if (mgcp_verify_ci(endp, ci) != 0)
 				goto error3;
 			break;
 		case 'Z':
 			silent = strcmp("noanswer", line + 3) == 0;
 			break;
 		default:
-			LOGP(DLMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
-				line[0], line[0], ENDPOINT_NUMBER(endp));
+			LOGP(DLMGCP, LOGL_NOTICE,
+			     "DLCX: endpoint:%x Unhandled MGCP option: '%c'/%d\n",
+			     ENDPOINT_NUMBER(endp), line[0], line[0]);
 			break;
 		}
 	}
@@ -1092,10 +960,11 @@
 	if (p->cfg->policy_cb) {
 		int rc;
 		rc = p->cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
-						MGCP_ENDP_DLCX, p->trans);
+				       MGCP_ENDP_DLCX, p->trans);
 		switch (rc) {
 		case MGCP_POLICY_REJECT:
-			LOGP(DLMGCP, LOGL_NOTICE, "DLCX rejected by policy on 0x%x\n",
+			LOGP(DLMGCP, LOGL_NOTICE,
+			     "DLCX: endpoint:%x rejected by policy\n",
 			     ENDPOINT_NUMBER(endp));
 			if (silent)
 				goto out_silent;
@@ -1103,7 +972,6 @@
 			break;
 		case MGCP_POLICY_DEFER:
 			/* stop processing */
-			delete_transcoder(endp);
 			return NULL;
 			break;
 		case MGCP_POLICY_CONT:
@@ -1112,17 +980,41 @@
 		}
 	}
 
-	/* free the connection */
-	LOGP(DLMGCP, LOGL_DEBUG, "Deleted endpoint on: 0x%x Server: %s:%u\n",
-		ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
+	/* find the connection */
+	if (mgcp_parse_ci(&conn_id, ci)) {
+		LOGP(DLMGCP, LOGL_ERROR,
+		     "DLCX: endpoint:%x insufficient parameters, missing ci (connectionIdentifier)\n",
+		     ENDPOINT_NUMBER(endp));
+		return create_err_response(endp, 400, "DLCX", p->trans);
+	}
 
-	/* save the statistics of the current call */
-	mgcp_format_stats(endp, stats, sizeof(stats));
+	conn = mgcp_conn_get_rtp(endp, conn_id);
+	if (!conn)
+		goto error3;
 
-	delete_transcoder(endp);
-	mgcp_release_endp(endp);
+	/* save the statistics of the current connection */
+	mgcp_format_stats(stats, sizeof(stats), conn->conn);
+
+	/* delete connection */
+	LOGP(DLMGCP, LOGL_DEBUG, "DLCX: endpoint:%x deleting conn:%s\n",
+	     ENDPOINT_NUMBER(endp), mgcp_conn_dump(conn->conn));
+	mgcp_conn_free(endp, conn_id);
+	LOGP(DLMGCP, LOGL_NOTICE,
+	     "DLCX: endpoint:%x connection successfully deleted\n",
+	     ENDPOINT_NUMBER(endp));
+
+	/* When all connections are closed, the endpoint will be released
+	 * in order to be ready to be used by another call. */
+	if (llist_count(&endp->conns) <= 0) {
+		mgcp_release_endp(endp);
+		LOGP(DLMGCP, LOGL_DEBUG,
+		     "DLCX: endpoint:%x endpoint released\n",
+		     ENDPOINT_NUMBER(endp));
+	}
+
 	if (p->cfg->change_cb)
-		p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX);
+		p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
+				  MGCP_ENDP_DLCX);
 
 	if (silent)
 		goto out_silent;
@@ -1132,13 +1024,27 @@
 	return create_err_response(endp, error_code, "DLCX", p->trans);
 
 out_silent:
+	LOGP(DLMGCP, LOGL_DEBUG, "DLCX: endpoint:%x silent exit\n",
+	     ENDPOINT_NUMBER(endp));
 	return NULL;
 }
 
+/* RSIP command handler, processes the received command */
 static struct msgb *handle_rsip(struct mgcp_parse_data *p)
 {
+	/* TODO: Also implement the resetting of a specific endpoint
+	 * to make mgcp_send_reset_ep() work. Currently this will call
+	 * mgcp_rsip_cb() in mgw_main.c, which sets reset_endpoints=1
+	 * to make read_call_agent() reset all endpoints when called
+	 * next time. In order to selectively reset endpoints some
+	 * mechanism to distinguish which endpoint shall be resetted
+	 * is needed */
+
+	LOGP(DLMGCP, LOGL_NOTICE, "RSIP: resetting all endpoints ...\n");
+
 	if (p->found != 0) {
-		LOGP(DLMGCP, LOGL_ERROR, "Failed to find the endpoint.\n");
+		LOGP(DLMGCP, LOGL_ERROR,
+		     "RSIP: failed to find the endpoint.\n");
 		return NULL;
 	}
 
@@ -1156,17 +1062,17 @@
 	return str[2];
 }
 
-/*
- * This can request like DTMF detection and forward, fax detection... it
+/* This can request like DTMF detection and forward, fax detection... it
  * can also request when the notification should be send and such. We don't
- * do this right now.
- */
+ * do this right now. */
 static struct msgb *handle_noti_req(struct mgcp_parse_data *p)
 {
 	int res = 0;
 	char *line;
 	char tone = CHAR_MAX;
 
+	LOGP(DLMGCP, LOGL_NOTICE, "RQNT: processing request for notification ...\n");
+
 	if (p->found != 0)
 		return create_err_response(NULL, 400, "RQNT", p->trans);
 
@@ -1186,29 +1092,38 @@
 		res = p->cfg->rqnt_cb(p->endp, tone);
 
 	return res == 0 ?
-		create_ok_response(p->endp, 200, "RQNT", p->trans) :
-		create_err_response(p->endp, res, "RQNT", p->trans);
+	    create_ok_response(p->endp, 200, "RQNT", p->trans) :
+	    create_err_response(p->endp, res, "RQNT", p->trans);
 }
 
+/* Connection keepalive timer, will take care that dummy packets are send
+ * regulary, so that NAT connections stay open */
 static void mgcp_keepalive_timer_cb(void *_tcfg)
 {
 	struct mgcp_trunk_config *tcfg = _tcfg;
+	struct mgcp_conn *conn;
 	int i;
+
 	LOGP(DLMGCP, LOGL_DEBUG, "Triggered trunk %d keepalive timer.\n",
 	     tcfg->trunk_nr);
 
 	if (tcfg->keepalive_interval <= 0)
 		return;
 
+	/* Send walk over all endpoints and send out dummy packets through
+	 * every connection present on each endpoint */
 	for (i = 1; i < tcfg->number_endpoints; ++i) {
 		struct mgcp_endpoint *endp = &tcfg->endpoints[i];
-		if (endp->conn_mode == MGCP_CONN_RECV_ONLY)
-			send_dummy(endp);
+		llist_for_each_entry(conn, &endp->conns, entry) {
+			if (conn->mode == MGCP_CONN_RECV_ONLY)
+				send_dummy(endp, &conn->u.rtp);
+		}
 	}
 
 	LOGP(DLMGCP, LOGL_DEBUG, "Rescheduling trunk %d keepalive timer.\n",
 	     tcfg->trunk_nr);
-	osmo_timer_schedule(&tcfg->keepalive_timer, tcfg->keepalive_interval, 0);
+	osmo_timer_schedule(&tcfg->keepalive_timer, tcfg->keepalive_interval,
+			    0);
 }
 
 void mgcp_trunk_set_keepalive(struct mgcp_trunk_config *tcfg, int interval)
@@ -1223,6 +1138,8 @@
 				    tcfg->keepalive_interval, 0);
 }
 
+/*! allocate configuration with default values.
+ *  (called once at startup by main function) */
 struct mgcp_config *mgcp_config_alloc(void)
 {
 	struct mgcp_config *cfg;
@@ -1233,15 +1150,14 @@
 		return NULL;
 	}
 
+	cfg->net_ports.range_start = RTP_PORT_DEFAULT_RANGE_START;
+	cfg->net_ports.range_end = RTP_PORT_DEFAULT_RANGE_END;
+	cfg->net_ports.last_port = cfg->net_ports.range_start;
+
 	cfg->source_port = 2427;
 	cfg->source_addr = talloc_strdup(cfg, "0.0.0.0");
 	cfg->osmux_addr = talloc_strdup(cfg, "0.0.0.0");
 
-	cfg->transcoder_remote_base = 4000;
-
-	cfg->bts_ports.base_port = RTP_PORT_DEFAULT;
-	cfg->net_ports.base_port = RTP_PORT_NET_DEFAULT;
-
 	cfg->rtp_processing_cb = &mgcp_rtp_processing_default;
 	cfg->setup_rtp_processing_cb = &mgcp_setup_rtp_processing_default;
 
@@ -1263,6 +1179,11 @@
 	return cfg;
 }
 
+/*! allocate configuration with default values.
+ *  (called once at startup by VTY)
+ *  \param[in] cfg mgcp configuration
+ *  \param[in] nr trunk number
+ *  \returns pointer to allocated trunk configuration */
 struct mgcp_trunk_config *mgcp_trunk_alloc(struct mgcp_config *cfg, int nr)
 {
 	struct mgcp_trunk_config *trunk;
@@ -1287,185 +1208,69 @@
 	return trunk;
 }
 
+/*! get trunk configuration by trunk number (index).
+ *  \param[in] cfg mgcp configuration
+ *  \param[in] index trunk number
+ *  \returns pointer to trunk configuration, NULL on error */
 struct mgcp_trunk_config *mgcp_trunk_num(struct mgcp_config *cfg, int index)
 {
 	struct mgcp_trunk_config *trunk;
 
 	llist_for_each_entry(trunk, &cfg->trunks, entry)
-		if (trunk->trunk_nr == index)
-			return trunk;
+	    if (trunk->trunk_nr == index)
+		return trunk;
 
 	return NULL;
 }
 
-static void mgcp_rtp_codec_reset(struct mgcp_rtp_codec *codec)
-{
-	codec->payload_type = -1;
-	talloc_free(codec->subtype_name);
-	codec->subtype_name = NULL;
-	talloc_free(codec->audio_name);
-	codec->audio_name = NULL;
-	codec->frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM;
-	codec->frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN;
-	codec->rate               = DEFAULT_RTP_AUDIO_DEFAULT_RATE;
-	codec->channels           = DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS;
-}
-
-static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end)
-{
-	if (end->local_alloc == PORT_ALLOC_DYNAMIC) {
-		mgcp_free_rtp_port(end);
-		end->local_port = 0;
-	}
-
-	end->packets = 0;
-	end->octets = 0;
-	end->dropped_packets = 0;
-	memset(&end->addr, 0, sizeof(end->addr));
-	end->rtp_port = end->rtcp_port = 0;
-	end->local_alloc = -1;
-	talloc_free(end->fmtp_extra);
-	end->fmtp_extra = NULL;
-	talloc_free(end->rtp_process_data);
-	end->rtp_process_data = NULL;
-
-	/* Set default values */
-	end->frames_per_packet  = 0; /* unknown */
-	end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS;
-	end->output_enabled	= 0;
-
-	mgcp_rtp_codec_reset(&end->codec);
-	mgcp_rtp_codec_reset(&end->alt_codec);
-}
-
-static void mgcp_rtp_end_init(struct mgcp_rtp_end *end)
-{
-	mgcp_rtp_end_reset(end);
-	end->rtp.fd = -1;
-	end->rtcp.fd = -1;
-}
-
+/*! allocate endpoints and set default values.
+ *  (called once at startup by VTY)
+ *  \param[in] tcfg trunk configuration
+ *  \returns 0 on success, -1 on failure */
 int mgcp_endpoints_allocate(struct mgcp_trunk_config *tcfg)
 {
 	int i;
 
-	/* Initialize all endpoints */
 	tcfg->endpoints = _talloc_zero_array(tcfg->cfg,
-				       sizeof(struct mgcp_endpoint),
-				       tcfg->number_endpoints, "endpoints");
+					     sizeof(struct mgcp_endpoint),
+					     tcfg->number_endpoints,
+					     "endpoints");
 	if (!tcfg->endpoints)
 		return -1;
 
 	for (i = 0; i < tcfg->number_endpoints; ++i) {
-		tcfg->endpoints[i].osmux.allocated_cid = -1;
-		tcfg->endpoints[i].ci = CI_UNUSED;
+		INIT_LLIST_HEAD(&tcfg->endpoints[i].conns);
 		tcfg->endpoints[i].cfg = tcfg->cfg;
 		tcfg->endpoints[i].tcfg = tcfg;
-		mgcp_rtp_end_init(&tcfg->endpoints[i].net_end);
-		mgcp_rtp_end_init(&tcfg->endpoints[i].bts_end);
-		mgcp_rtp_end_init(&tcfg->endpoints[i].trans_net);
-		mgcp_rtp_end_init(&tcfg->endpoints[i].trans_bts);
+
+		/* NOTE: Currently all endpoints are of type RTP, this will
+		 * change when new variations are implemented */
+		tcfg->endpoints[i].type = &ep_typeset.rtp;
 	}
 
 	return 0;
 }
 
+/*! relase endpoint, all open connections are closed.
+ *  \param[in] endp endpoint to release */
 void mgcp_release_endp(struct mgcp_endpoint *endp)
 {
-	LOGP(DLMGCP, LOGL_DEBUG, "Releasing endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp));
-	endp->ci = CI_UNUSED;
-	endp->allocated = 0;
+	LOGP(DLMGCP, LOGL_DEBUG, "Releasing endpoint:%x\n",
+	     ENDPOINT_NUMBER(endp));
 
+	/* Normally this function should only be called wehen
+	 * all connections have been removed already. In case
+	 * that there are still connections open (e.g. when
+	 * RSIP is executed), free them all at once. */
+	mgcp_conn_free_all(endp);
+
+	/* Reset endpoint parameters and states */
 	talloc_free(endp->callid);
 	endp->callid = NULL;
-
 	talloc_free(endp->local_options.string);
 	endp->local_options.string = NULL;
 	talloc_free(endp->local_options.codec);
 	endp->local_options.codec = NULL;
-
-	mgcp_rtp_end_reset(&endp->bts_end);
-	mgcp_rtp_end_reset(&endp->net_end);
-	mgcp_rtp_end_reset(&endp->trans_net);
-	mgcp_rtp_end_reset(&endp->trans_bts);
-	endp->type = MGCP_RTP_DEFAULT;
-
-	memset(&endp->net_state, 0, sizeof(endp->net_state));
-	memset(&endp->bts_state, 0, sizeof(endp->bts_state));
-
-	endp->conn_mode = endp->orig_mode = MGCP_CONN_NONE;
-
-	if (endp->osmux.state == OSMUX_STATE_ENABLED)
-		osmux_disable_endpoint(endp);
-
-	/* release the circuit ID if it had been allocated */
-	osmux_release_cid(endp);
-
-	memset(&endp->taps, 0, sizeof(endp->taps));
-}
-
-void mgcp_initialize_endp(struct mgcp_endpoint *endp)
-{
-	return mgcp_release_endp(endp);
-}
-
-static int send_trans(struct mgcp_config *cfg, const char *buf, int len)
-{
-	struct sockaddr_in addr;
-
-	memset(&addr, 0, sizeof(addr));
-	addr.sin_family = AF_INET;
-	addr.sin_addr = cfg->transcoder_in;
-	addr.sin_port = htons(2427);
-	return sendto(cfg->gw_fd.bfd.fd, buf, len, 0,
-		      (struct sockaddr *) &addr, sizeof(addr));
-}
-
-static void send_msg(struct mgcp_endpoint *endp, int endpoint, int port,
-		     const char *msg, const char *mode)
-{
-	char buf[2096];
-	int len;
-	int nchars;
-
-	/* hardcoded to AMR right now, we do not know the real type at this point */
-	len = snprintf(buf, sizeof(buf),
-			"%s 42 %x@mgw MGCP 1.0\r\n"
-			"C: 4256\r\n"
-			"M: %s\r\n"
-			"\r\n",
-			msg, endpoint, mode);
-
-	if (len < 0)
-		return;
-
-	nchars = write_response_sdp(endp, buf + len, sizeof(buf) + len - 1, NULL);
-	if (nchars < 0)
-		return;
-
-	len += nchars;
-
-	buf[sizeof(buf) - 1] = '\0';
-
-	send_trans(endp->cfg, buf, len);
-}
-
-static void send_dlcx(struct mgcp_endpoint *endp, int endpoint)
-{
-	char buf[2096];
-	int len;
-
-	len = snprintf(buf, sizeof(buf),
-			"DLCX 43 %x@mgw MGCP 1.0\r\n"
-			"C: 4256\r\n"
-			, endpoint);
-
-	if (len < 0)
-		return;
-
-	buf[sizeof(buf) - 1] = '\0';
-
-	send_trans(endp->cfg, buf, len);
 }
 
 static int send_agent(struct mgcp_config *cfg, const char *buf, int len)
@@ -1473,168 +1278,47 @@
 	return write(cfg->gw_fd.bfd.fd, buf, len);
 }
 
+/*! Reset all endpoints by sending RSIP message to self.
+ *  (called by VTY)
+ *  \param[in] endp trunk endpoint
+ *  \param[in] endpoint number
+ *  \returns 0 on success, -1 on error */
 int mgcp_send_reset_all(struct mgcp_config *cfg)
 {
+	int rc;
+
 	static const char mgcp_reset[] = {
-	    "RSIP 1 *@mgw MGCP 1.0\r\n"
+		"RSIP 1 *@mgw MGCP 1.0\r\n"
 	};
 
-	return send_agent(cfg, mgcp_reset, sizeof mgcp_reset -1);
+	rc = send_agent(cfg, mgcp_reset, sizeof mgcp_reset - 1);
+	if (rc <= 0)
+		return -1;
+
+	return 0;
 }
 
+/*! Reset a single endpoint by sending RSIP message to self.
+ *  (called by VTY)
+ *  \param[in] endp trunk endpoint
+ *  \param[in] endpoint number
+ *  \returns 0 on success, -1 on error */
 int mgcp_send_reset_ep(struct mgcp_endpoint *endp, int endpoint)
 {
 	char buf[128];
 	int len;
+	int rc;
 
 	len = snprintf(buf, sizeof(buf),
-			"RSIP 39 %x@mgw MGCP 1.0\r\n"
-			, endpoint);
+		       "RSIP 39 %x@mgw MGCP 1.0\r\n", endpoint);
 	if (len < 0)
-		return len;
+		return -1;
 
 	buf[sizeof(buf) - 1] = '\0';
 
-	return send_agent(endp->cfg, buf, len);
-}
-
-static int setup_rtp_processing(struct mgcp_endpoint *endp)
-{
-	int rc = 0;
-	struct mgcp_config *cfg = endp->cfg;
-
-	if (endp->type != MGCP_RTP_DEFAULT)
-		return 0;
-
-	if (endp->conn_mode == MGCP_CONN_LOOPBACK)
-		return 0;
-
-	if (endp->conn_mode & MGCP_CONN_SEND_ONLY)
-		rc |= cfg->setup_rtp_processing_cb(endp, &endp->net_end, &endp->bts_end);
-	else
-		rc |= cfg->setup_rtp_processing_cb(endp, &endp->net_end, NULL);
-
-	if (endp->conn_mode & MGCP_CONN_RECV_ONLY)
-		rc |= cfg->setup_rtp_processing_cb(endp, &endp->bts_end, &endp->net_end);
-	else
-		rc |= cfg->setup_rtp_processing_cb(endp, &endp->bts_end, NULL);
-	return rc;
-}
-
-static void create_transcoder(struct mgcp_endpoint *endp)
-{
-	int port;
-	int in_endp = ENDPOINT_NUMBER(endp);
-	int out_endp = endp_back_channel(in_endp);
-
-	if (endp->type != MGCP_RTP_TRANSCODED)
-		return;
-
-	send_msg(endp, in_endp, endp->trans_bts.local_port, "CRCX", "sendrecv");
-	send_msg(endp, in_endp, endp->trans_bts.local_port, "MDCX", "sendrecv");
-	send_msg(endp, out_endp, endp->trans_net.local_port, "CRCX", "sendrecv");
-	send_msg(endp, out_endp, endp->trans_net.local_port, "MDCX", "sendrecv");
-
-	port = rtp_calculate_port(in_endp, endp->cfg->transcoder_remote_base);
-	endp->trans_bts.rtp_port = htons(port);
-	endp->trans_bts.rtcp_port = htons(port + 1);
-
-	port = rtp_calculate_port(out_endp, endp->cfg->transcoder_remote_base);
-	endp->trans_net.rtp_port = htons(port);
-	endp->trans_net.rtcp_port = htons(port + 1);
-}
-
-static void delete_transcoder(struct mgcp_endpoint *endp)
-{
-	int in_endp = ENDPOINT_NUMBER(endp);
-	int out_endp = endp_back_channel(in_endp);
-
-	if (endp->type != MGCP_RTP_TRANSCODED)
-		return;
-
-	send_dlcx(endp, in_endp);
-	send_dlcx(endp, out_endp);
-}
-
-int mgcp_reset_transcoder(struct mgcp_config *cfg)
-{
-	if (!cfg->transcoder_ip)
-		return 0;
-
-	static const char mgcp_reset[] = {
-	    "RSIP 1 13@mgw MGCP 1.0\r\n"
-	};
-
-	return send_trans(cfg, mgcp_reset, sizeof mgcp_reset -1);
-}
-
-void mgcp_format_stats(struct mgcp_endpoint *endp, char *msg, size_t size)
-{
-	uint32_t expected, jitter;
-	int ploss;
-	int nchars;
-	mgcp_state_calc_loss(&endp->net_state, &endp->net_end,
-				&expected, &ploss);
-	jitter = mgcp_state_calc_jitter(&endp->net_state);
-
-	nchars = snprintf(msg, size,
-			  "\r\nP: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
-			  endp->bts_end.packets, endp->bts_end.octets,
-			  endp->net_end.packets, endp->net_end.octets,
-			  ploss, jitter);
-	if (nchars < 0 || nchars >= size)
-		goto truncate;
-
-	msg += nchars;
-	size -= nchars;
-
-	/* Error Counter */
-	nchars = snprintf(msg, size,
-			  "\r\nX-Osmo-CP: EC TIS=%u, TOS=%u, TIR=%u, TOR=%u",
-			  endp->net_state.in_stream.err_ts_counter,
-			  endp->net_state.out_stream.err_ts_counter,
-			  endp->bts_state.in_stream.err_ts_counter,
-			  endp->bts_state.out_stream.err_ts_counter);
-	if (nchars < 0 || nchars >= size)
-		goto truncate;
-
-	msg += nchars;
-	size -= nchars;
-
-	if (endp->osmux.state == OSMUX_STATE_ENABLED) {
-		snprintf(msg, size,
-			 "\r\nX-Osmux-ST: CR=%u, BR=%u",
-			 endp->osmux.stats.chunks,
-			 endp->osmux.stats.octets);
-	}
-truncate:
-	msg[size - 1] = '\0';
-}
-
-int mgcp_parse_stats(struct msgb *msg, uint32_t *ps, uint32_t *os,
-		uint32_t *pr, uint32_t *_or, int *loss, uint32_t *jitter)
-{
-	char *line, *save;
-	int rc;
-
-	/* initialize with bad values */
-	*ps = *os = *pr = *_or = *jitter = UINT_MAX;
-	*loss = INT_MAX;
-
-
-	line = strtok_r((char *) msg->l2h, "\r\n", &save);
-	if (!line)
+	rc = send_agent(endp->cfg, buf, len);
+	if (rc <= 0)
 		return -1;
 
-	/* this can only parse the message that is created above... */
-	for_each_non_empty_line(line, save) {
-		switch (line[0]) {
-		case 'P':
-			rc = sscanf(line, "P: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
-					ps, os, pr, _or, loss, jitter);
-			return rc == 6 ? 0 : -1;
-		}
-	}
-
-	return -1;
+	return 0;
 }