Merge remote branch 'goeller/master'
diff --git a/openbsc/src/bsc_mgcp.c b/openbsc/src/bsc_mgcp.c
index fff6d60..ecc13ca 100644
--- a/openbsc/src/bsc_mgcp.c
+++ b/openbsc/src/bsc_mgcp.c
@@ -64,6 +64,7 @@
 static int audio_loop = 0;
 static int early_bind = 0;
 
+static char *forward_ip = NULL;
 static char *config_file = "mgcp.cfg";
 
 /* used by msgb and mgcp */
@@ -909,6 +910,8 @@
 	vty_out(vty, "  sdp audio payload name %s%s", audio_name, VTY_NEWLINE);
 	vty_out(vty, "  loop %u%s", !!audio_loop, VTY_NEWLINE);
 	vty_out(vty, "  endpoints %u%s", number_endpoints, VTY_NEWLINE);
+	if (forward_ip)
+		vty_out(vty, " forward audio %s%s", forward_ip, VTY_NEWLINE);
 
 	return CMD_SUCCESS;
 }
@@ -1055,6 +1058,17 @@
 	return CMD_SUCCESS;
 }
 
+DEFUN(cfg_mgcp_forward,
+      cfg_mgcp_forward_cmd,
+      "forward audio IP",
+      "Forward packets from and to the IP. This disables most of the MGCP feature.")
+{
+	if (forward_ip)
+		talloc_free(forward_ip);
+	forward_ip = talloc_strdup(tall_bsc_ctx, argv[0]);
+	return CMD_SUCCESS;
+}
+
 int bsc_vty_init(struct gsm_network *dummy)
 {
 	cmd_init(1);
@@ -1076,6 +1090,7 @@
 	install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_name_cmd);
 	install_element(MGCP_NODE, &cfg_mgcp_loop_cmd);
 	install_element(MGCP_NODE, &cfg_mgcp_number_endp_cmd);
+	install_element(MGCP_NODE, &cfg_mgcp_forward_cmd);
 	return 0;
 }
 
@@ -1123,37 +1138,66 @@
 		endpoints[i].ci = CI_UNUSED;
 	}
 
-	/* initialize the socket */
-	bfd.when = BSC_FD_READ;
-	bfd.cb = read_call_agent;
-	bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
-	if (bfd.fd < 0) {
-		perror("Gateway failed to listen");
-		return -1;
-	}
+	/*
+	 * This application supports two modes.
+         *    1.) a true MGCP gateway with support for AUEP, CRCX, MDCX, DLCX
+         *    2.) plain forwarding of RTP packets on the endpoints.
+	 * both modes are mutual exclusive
+	 */
+	if (forward_ip) {
 
-	setsockopt(bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+		if (!early_bind) {
+			DEBUGP(DMGCP, "Forwarding requires early bind.\n");
+			return -1;
+		}
 
-	memset(&addr, 0, sizeof(addr));
-	addr.sin_family = AF_INET;
-	addr.sin_port = htons(source_port);
-	inet_aton(source_addr, &addr.sin_addr);
+		/*
+		 * Store the forward IP and assign a ci. For early bind
+		 * the sockets will be created after this.
+		 */
+		for (i = 1; i < number_endpoints; ++i) {
+			struct mgcp_endpoint *endp = &endpoints[i];
+			inet_aton(forward_ip, &endp->remote);
+			endp->ci = CI_UNUSED + 23;
+			endp->rtp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port));
+			endp->rtcp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port) + 1);
+		}
 
-	if (bind(bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("Gateway failed to bind");
-		return -1;
-	}
+		DEBUGP(DMGCP, "Configured for Audio Forwarding.\n");
+	} else {
+		bfd.when = BSC_FD_READ;
+		bfd.cb = read_call_agent;
+		bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
+		if (bfd.fd < 0) {
+			perror("Gateway failed to listen");
+			return -1;
+		}
 
-	bfd.data = msgb_alloc(4096, "mgcp-msg");
-	if (!bfd.data) {
-		fprintf(stderr, "Gateway memory error.\n");
-		return -1;
-	}
+		setsockopt(bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+
+		memset(&addr, 0, sizeof(addr));
+		addr.sin_family = AF_INET;
+		addr.sin_port = htons(source_port);
+		inet_aton(source_addr, &addr.sin_addr);
+
+		if (bind(bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+			perror("Gateway failed to bind");
+			return -1;
+		}
+
+		bfd.data = msgb_alloc(4096, "mgcp-msg");
+		if (!bfd.data) {
+			fprintf(stderr, "Gateway memory error.\n");
+			return -1;
+		}
 
 
-	if (bsc_register_fd(&bfd) != 0) {
-		DEBUGP(DMGCP, "Failed to register the fd\n");
-		return -1;
+		if (bsc_register_fd(&bfd) != 0) {
+			DEBUGP(DMGCP, "Failed to register the fd\n");
+			return -1;
+		}
+
+		DEBUGP(DMGCP, "Configured for MGCP.\n");
 	}
 
 	/* initialisation */
diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c
index 694ae06..1f2e1a1 100644
--- a/openbsc/src/gsm_data.c
+++ b/openbsc/src/gsm_data.c
@@ -191,7 +191,7 @@
 	if (!bts)
 		return NULL;
 
-	if (!model) {
+	if (!model && type != GSM_BTS_TYPE_UNKNOWN) {
 		talloc_free(bts);
 		return NULL;
 	}
diff --git a/openbsc/tests/channel/Makefile.am b/openbsc/tests/channel/Makefile.am
index 564cbaf..6b9f6e3 100644
--- a/openbsc/tests/channel/Makefile.am
+++ b/openbsc/tests/channel/Makefile.am
@@ -13,6 +13,9 @@
 	$(top_srcdir)/src/talloc.c \
 	$(top_srcdir)/src/gsm_data.c \
 	$(top_srcdir)/src/signal.c \
-	$(top_srcdir)/src/statistics.c
+	$(top_srcdir)/src/statistics.c \
+	$(top_srcdir)/src/bts_ipaccess_nanobts.c \
+	$(top_srcdir)/src/bts_siemens_bs11.c \
+	$(top_srcdir)/src/tlv_parser.c
 channel_test_LDADD = -ldl -ldbi
 
diff --git a/openbsc/tests/channel/channel_test.c b/openbsc/tests/channel/channel_test.c
index 1b01878..36d0572 100644
--- a/openbsc/tests/channel/channel_test.c
+++ b/openbsc/tests/channel/channel_test.c
@@ -77,3 +77,5 @@
 void input_event() {}
 void sms_alloc() {}
 
+struct tlv_definition nm_att_tlvdef;
+