Merge branch 'on-waves/mgcp'
diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h
index 918ba4b..62161fd 100644
--- a/openbsc/include/openbsc/mgcp_internal.h
+++ b/openbsc/include/openbsc/mgcp_internal.h
@@ -28,11 +28,21 @@
 
 #define CI_UNUSED 0
 
+enum mgcp_connection_mode {
+	MGCP_CONN_NONE = 0,
+	MGCP_CONN_RECV_ONLY = 1,
+	MGCP_CONN_SEND_ONLY = 2,
+	MGCP_CONN_RECV_SEND = MGCP_CONN_RECV_ONLY | MGCP_CONN_SEND_ONLY,
+	MGCP_CONN_LOOPBACK  = 4,
+};
+
+
 struct mgcp_endpoint {
 	int ci;
 	char *callid;
 	char *local_options;
 	int conn_mode;
+	int orig_mode;
 
 	int bts_payload_type;
 	int net_payload_type;
diff --git a/openbsc/src/mgcp/mgcp_network.c b/openbsc/src/mgcp/mgcp_network.c
index cc1bf44..5923fea 100644
--- a/openbsc/src/mgcp/mgcp_network.c
+++ b/openbsc/src/mgcp/mgcp_network.c
@@ -204,6 +204,10 @@
 	if (cfg->audio_loop)
 		dest = !dest;
 
+	/* Loop based on the conn_mode, maybe undoing the above */
+	if (endp->conn_mode == MGCP_CONN_LOOPBACK)
+		dest = !dest;
+
 	if (dest == DEST_NETWORK) {
 		if (proto == PROTO_RTP)
 			patch_and_count(&endp->bts_seq_no, &endp->bts_lost_no,
diff --git a/openbsc/src/mgcp/mgcp_protocol.c b/openbsc/src/mgcp/mgcp_protocol.c
index 8131277..5883c15 100644
--- a/openbsc/src/mgcp/mgcp_protocol.c
+++ b/openbsc/src/mgcp/mgcp_protocol.c
@@ -38,13 +38,6 @@
 #include <openbsc/mgcp.h>
 #include <openbsc/mgcp_internal.h>
 
-enum mgcp_connection_mode {
-	MGCP_CONN_NONE = 0,
-	MGCP_CONN_RECV_ONLY = 1,
-	MGCP_CONN_SEND_ONLY = 2,
-	MGCP_CONN_RECV_SEND = MGCP_CONN_RECV_ONLY | MGCP_CONN_SEND_ONLY,
-};
-
 /**
  * Macro for tokenizing MGCP messages and SDP in one go.
  *
@@ -364,6 +357,8 @@
 		*conn_mode = MGCP_CONN_RECV_ONLY;
 	else if (strcmp(msg, "sendrecv") == 0)
 		*conn_mode = MGCP_CONN_RECV_SEND;
+	else if (strcmp(msg, "loopback") == 0)
+		*conn_mode = MGCP_CONN_LOOPBACK;
 	else {
 		LOGP(DMGCP, LOGL_ERROR, "Unknown connection mode: '%s'\n", msg);
 		ret = -1;
@@ -414,6 +409,8 @@
 		    error_code = 517;
 		    goto error2;
 		}
+
+		endp->orig_mode = endp->conn_mode;
 		break;
 	default:
 		LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
@@ -518,6 +515,7 @@
 		    error_code = 517;
 		    goto error3;
 		}
+		endp->orig_mode = endp->conn_mode;
 		break;
 	case 'Z':
 		silent = strcmp("noanswer", (const char *)&msg->l3h[line_start + 3]) == 0;
@@ -767,4 +765,6 @@
 
 	endp->net_seq_no = endp->bts_seq_no = 0;
 	endp->net_lost_no = endp->bts_lost_no = 0;
+
+	endp->conn_mode = endp->orig_mode = MGCP_CONN_NONE;
 }
diff --git a/openbsc/src/mgcp/mgcp_vty.c b/openbsc/src/mgcp/mgcp_vty.c
index 49974c1..323b311 100644
--- a/openbsc/src/mgcp/mgcp_vty.c
+++ b/openbsc/src/mgcp/mgcp_vty.c
@@ -254,12 +254,41 @@
 	return CMD_SUCCESS;
 }
 
+DEFUN(loop_endp,
+      loop_endp_cmd,
+      "loop-endpoint NAME (0|1)",
+      "Loop a given endpoint\n"
+      "The name in hex of the endpoint\n" "Enable/Disable the loop\n")
+{
+	struct mgcp_endpoint *endp;
+
+	int endp_no = strtoul(argv[0], NULL, 16);
+	if (endp_no < 1 || endp_no >= g_cfg->number_endpoints) {
+		vty_out(vty, "Loopback number %s/%d is invalid.%s",
+		argv[0], endp_no, VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+
+	endp = &g_cfg->endpoints[endp_no];
+	int loop = atoi(argv[1]);
+
+	if (loop)
+		endp->conn_mode = MGCP_CONN_LOOPBACK;
+	else
+		endp->conn_mode = endp->orig_mode;
+
+	return CMD_SUCCESS;
+}
+
 int mgcp_vty_init(void)
 {
 	install_element_ve(&show_mgcp_cmd);
+	install_element(ENABLE_NODE, &loop_endp_cmd);
 
 	install_element(CONFIG_NODE, &cfg_mgcp_cmd);
 	install_node(&mgcp_node, config_write_mgcp);
+
 	install_default(MGCP_NODE);
 	install_element(MGCP_NODE, &ournode_exit_cmd);
 	install_element(MGCP_NODE, &ournode_end_cmd);