Merge branch 'on-waves/mgcp'
diff --git a/openbsc/contrib/mgcp_server.py b/openbsc/contrib/mgcp_server.py
index cf3ef38..05c489d 100755
--- a/openbsc/contrib/mgcp_server.py
+++ b/openbsc/contrib/mgcp_server.py
@@ -10,7 +10,7 @@
 audit_packet = """AUEP %d 13@mgw MGCP 1.0\r\n"""
 crcx_packet = """CRCX %d 14@mgw MGCP 1.0\r\nC: 4a84ad5d25f\r\nL: p:20, a:GSM-EFR, nt:IN\r\nM: recvonly\r\n"""
 dlcx_packet = """DLCX %d 14@mgw MGCP 1.0\r\nC: 4a84ad5d25f\r\nI: %d\r\n"""
-mdcx_packet = """MDCX %d 14@mgw MGCP 1.0\r\nC: 4a84ad5d25f\r\nI: %d\r\nL: p:20, a:GSM-EFR, nt:IN\r\nM: recvonly\r\n\r\nv=0\r\no=- 258696477 0 IN IP4 172.16.1.107\r\ns=-\r\nc=IN IP4 172.16.1.107\r\nt=0 0\r\nm=audio 4400 RTP/AVP 127\r\na=rtpmap:127 GSM-EFR/8000/1\r\na=ptime:20\r\na=recvonly\r\nm=image 4402 udptl t38\r\na=T38FaxVersion:0\r\na=T38MaxBitRate:14400\r\n"""
+mdcx_packet = """MDCX %d 14@mgw MGCP 1.0\r\nC: 4a84ad5d25f\r\nI: %d\r\nL: p:20, a:GSM-EFR, nt:IN\r\nM: recvonly\r\n\r\nv=0\r\no=- 258696477 0 IN IP4 172.16.1.107\r\ns=-\r\nc=IN IP4 172.16.1.107\r\nt=0 0\r\nm=audio 6666 RTP/AVP 127\r\na=rtpmap:127 GSM-EFR/8000/1\r\na=ptime:20\r\na=recvonly\r\nm=image 4402 udptl t38\r\na=T38FaxVersion:0\r\na=T38MaxBitRate:14400\r\n"""
 
 def hexdump(src, length=8):
     """Recipe is from http://code.activestate.com/recipes/142812/"""
@@ -25,15 +25,24 @@
 
 server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 server_socket.bind(("127.0.0.1", MGCP_CALLAGENT_PORT))
-server_socket.setblocking(0)
+server_socket.setblocking(1)
 
-
-def send_receive(packet):
+last_ci = 1
+def send_and_receive(packet):
+    global last_ci
     server_socket.sendto(packet, ("127.0.0.1", MGCP_GATEWAY_PORT))
     try:
         data, addr = server_socket.recvfrom(4096)
+
+        # attempt to store the CI of the response
+        list = data.split("\n")
+        for item in list:
+           if item.startswith("I: "):
+               last_ci = int(item[3:])
+
         print hexdump(data), addr
-    except socket.error:
+    except socket.error, e:
+        print e
         pass
 
 def generate_tid():
@@ -42,13 +51,10 @@
 
 
 
-i = 1
 while True:
-    send_receive(rsip_resp)
-    send_receive(audit_packet)
-    send_receive(crcx_packet % generate_tid() )
-    send_receive(mdcx_packet % (generate_tid(), i))
-    send_receive(dlcx_packet % (generate_tid(), i))
-    i = i + 1
+    send_and_receive(audit_packet % generate_tid())
+    send_and_receive(crcx_packet % generate_tid() )
+    send_and_receive(mdcx_packet % (generate_tid(), last_ci))
+    send_and_receive(dlcx_packet % (generate_tid(), last_ci))
 
     time.sleep(3)
diff --git a/openbsc/include/openbsc/mgcp.h b/openbsc/include/openbsc/mgcp.h
index f7e800b..71b7fc1 100644
--- a/openbsc/include/openbsc/mgcp.h
+++ b/openbsc/include/openbsc/mgcp.h
@@ -77,6 +77,7 @@
 
 typedef int (*mgcp_change)(struct mgcp_config *cfg, int endpoint, int state, int local_rtp);
 typedef int (*mgcp_policy)(struct mgcp_config *cfg, int endpoint, int state, const char *transactio_id);
+typedef int (*mgcp_reset)(struct mgcp_config *cfg);
 
 struct mgcp_config {
 	int source_port;
@@ -84,6 +85,7 @@
 	char *source_addr;
 	unsigned int number_endpoints;
 	char *bts_ip;
+	char *call_agent_addr;
 
 	struct in_addr bts_in;
 	char *audio_name;
@@ -95,8 +97,12 @@
 	char *forward_ip;
 	int forward_port;
 
+	/* spec handling */
+	int force_realloc;
+
 	mgcp_change change_cb;
 	mgcp_policy policy_cb;
+	mgcp_reset reset_cb;
 	void *data;
 
 	struct mgcp_endpoint *endpoints;
@@ -115,8 +121,15 @@
  * format helper functions
  */
 struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg);
-struct msgb *mgcp_create_rsip(void);
 struct msgb *mgcp_create_response_with_data(int code, const char *msg, const char *trans, const char *data);
 
+/* adc helper */
+static inline int mgcp_timeslot_to_endpoint(int multiplex, int timeslot)
+{
+	if (timeslot == 0)
+		timeslot = 1;
+	return timeslot + (31 * multiplex);
+}
+
 
 #endif
diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h
index 10d0ca6..3a28324 100644
--- a/openbsc/include/openbsc/mgcp_internal.h
+++ b/openbsc/include/openbsc/mgcp_internal.h
@@ -57,8 +57,21 @@
 
 	/* backpointer */
 	struct mgcp_config *cfg;
+
+	/* statistics */
+	unsigned int in_bts;
+	unsigned int in_remote;
 };
 
 #define ENDPOINT_NUMBER(endp) abs(endp - endp->cfg->endpoints)
 
+struct mgcp_msg_ptr {
+	unsigned int start;
+	unsigned int length;
+};
+
+int mgcp_analyze_header(struct mgcp_config *cfg, struct msgb *msg,
+			struct mgcp_msg_ptr *ptr, int size,
+			const char **transaction_id, struct mgcp_endpoint **endp);
+
 #endif
diff --git a/openbsc/src/mgcp/mgcp_main.c b/openbsc/src/mgcp/mgcp_main.c
index 147a765..5e337e9 100644
--- a/openbsc/src/mgcp/mgcp_main.c
+++ b/openbsc/src/mgcp/mgcp_main.c
@@ -38,8 +38,11 @@
 #include <openbsc/gsm_data.h>
 #include <osmocore/select.h>
 #include <openbsc/mgcp.h>
+#include <openbsc/mgcp_internal.h>
 #include <openbsc/telnet_interface.h>
 
+#include <vty/command.h>
+
 #include "../../bscconfig.h"
 
 /* this is here for the vty... it will never be called */
@@ -51,8 +54,9 @@
 #warning "Make use of the rtp proxy code"
 
 static struct bsc_fd bfd;
-static int first_request = 1;
 static struct mgcp_config *cfg;
+static int reset_endpoints = 0;
+
 const char *openbsc_version = "OpenBSC MGCP " PACKAGE_VERSION;
 const char *openbsc_copyright =
 	"Copyright (C) 2009-2010 Holger Freyther and On-Waves\n"
@@ -74,10 +78,10 @@
 	printf(" -c --config-file filename The config file to use.\n");
 }
 
-static void print_version()
+static void print_mgcp_version()
 {
 	printf("%s\n\n", openbsc_version);
-	printf(openbsc_copyright);
+	printf("%s", openbsc_copyright);
 }
 
 static void handle_options(int argc, char** argv)
@@ -105,7 +109,7 @@
 			config_file = talloc_strdup(tall_bsc_ctx, optarg);
 			break;
 		case 'V':
-			print_version();
+			print_mgcp_version();
 			exit(0);
 			break;
 		default:
@@ -115,12 +119,21 @@
 	}
 }
 
+/* simply remember this */
+static int mgcp_rsip_cb(struct mgcp_config *cfg)
+{
+	reset_endpoints = 1;
+
+	return 0;
+}
+
 static int read_call_agent(struct bsc_fd *fd, unsigned int what)
 {
 	struct sockaddr_in addr;
 	socklen_t slen = sizeof(addr);
 	struct msgb *msg;
 	struct msgb *resp;
+	int i;
 
 	msg = (struct msgb *) fd->data;
 
@@ -136,18 +149,6 @@
 		return -1;
 	}
 
-	if (first_request) {
-		first_request = 0;
-		resp = mgcp_create_rsip();
-
-		if (resp) {
-			sendto(bfd.fd, resp->l2h, msgb_l2len(resp), 0,
-				(struct sockaddr *) &addr, sizeof(addr));
-			msgb_free(resp);
-		}
-		return 0;
-        }
-
 	/* handle message now */
 	msg->l2h = msgb_put(msg, rc);
 	resp = mgcp_handle_message(cfg, msg);
@@ -157,6 +158,16 @@
 		sendto(bfd.fd, resp->l2h, msgb_l2len(resp), 0, (struct sockaddr *) &addr, sizeof(addr));
 		msgb_free(resp);
 	}
+
+	if (reset_endpoints) {
+		LOGP(DMGCP, LOGL_NOTICE, "Asked to reset endpoints.\n");
+		reset_endpoints = 0;
+
+		/* is checking in_addr.s_addr == INADDR_LOOPBACK making it more secure? */
+		for (i = 1; i < cfg->number_endpoints; ++i)
+			mgcp_free_endp(&cfg->endpoints[i]);
+	}
+
 	return 0;
 }
 
@@ -186,6 +197,8 @@
 	if (rc < 0)
 		return rc;
 
+	/* set some callbacks */
+	cfg->reset_cb = mgcp_rsip_cb;
 
         /* we need to bind a socket */
         if (rc == 0) {
@@ -217,11 +230,11 @@
 
 
 		if (bsc_register_fd(&bfd) != 0) {
-			DEBUGP(DMGCP, "Failed to register the fd\n");
+			LOGP(DMGCP, LOGL_FATAL, "Failed to register the fd\n");
 			return -1;
 		}
 
-		DEBUGP(DMGCP, "Configured for MGCP.\n");
+		LOGP(DMGCP, LOGL_NOTICE, "Configured for MGCP.\n");
 	}
 
 	/* initialisation */
@@ -235,3 +248,14 @@
 
 	return 0;
 }
+
+struct gsm_network;
+int bsc_vty_init(struct gsm_network *dummy)
+{
+	cmd_init(1);
+	vty_init();
+
+        mgcp_vty_init();
+	return 0;
+}
+
diff --git a/openbsc/src/mgcp/mgcp_network.c b/openbsc/src/mgcp/mgcp_network.c
index b76ca47..cd10d2a 100644
--- a/openbsc/src/mgcp/mgcp_network.c
+++ b/openbsc/src/mgcp/mgcp_network.c
@@ -25,6 +25,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <endian.h>
+#include <errno.h>
 
 #include <sys/socket.h>
 #include <arpa/inet.h>
@@ -90,6 +91,9 @@
 	if (len < sizeof(*rtp_hdr))
 		return;
 
+	if (payload < 0)
+		return;
+
 	rtp_hdr = (struct rtp_hdr *) data;
 	rtp_hdr->payload_type = payload;
 }
@@ -119,16 +123,14 @@
 	rc = recvfrom(fd->fd, &buf, sizeof(buf), 0,
 			    (struct sockaddr *) &addr, &slen);
 	if (rc < 0) {
-		LOGP(DMGCP, LOGL_ERROR, "Failed to receive message on: 0x%x\n",
-			ENDPOINT_NUMBER(endp));
+		LOGP(DMGCP, LOGL_ERROR, "Failed to receive message on: 0x%x errno: %d/%s\n",
+			ENDPOINT_NUMBER(endp), errno, strerror(errno));
 		return -1;
 	}
 
 	/* do not forward aynthing... maybe there is a packet from the bts */
-	if (endp->ci == CI_UNUSED) {
-		LOGP(DMGCP, LOGL_ERROR, "Unknown message on endpoint: 0x%x\n", ENDPOINT_NUMBER(endp));
+	if (endp->ci == CI_UNUSED)
 		return -1;
-	}
 
 	/*
 	 * Figure out where to forward it to. This code assumes that we
@@ -146,7 +148,9 @@
 	/* We have no idea who called us, maybe it is the BTS. */
 	if (dest == DEST_NETWORK && (endp->bts_rtp == 0 || cfg->forward_ip)) {
 		/* it was the BTS... */
-		if (!cfg->bts_ip || memcmp(&addr.sin_addr, &cfg->bts_in, sizeof(cfg->bts_in)) == 0) {
+		if (!cfg->bts_ip
+		    || memcmp(&addr.sin_addr, &cfg->bts_in, sizeof(cfg->bts_in)) == 0
+		    || memcmp(&addr.sin_addr, &endp->bts, sizeof(endp->bts)) == 0) {
 			if (fd == &endp->local_rtp) {
 				endp->bts_rtp = addr.sin_port;
 			} else {
@@ -159,6 +163,12 @@
 		}
 	}
 
+	/* do this before the loop handling */
+	if (dest == DEST_NETWORK)
+		++endp->in_bts;
+	else
+		++endp->in_remote;
+
 	/* dispatch */
 	if (cfg->audio_loop)
 		dest = !dest;
diff --git a/openbsc/src/mgcp/mgcp_protocol.c b/openbsc/src/mgcp/mgcp_protocol.c
index f7ef547..76eb7c2 100644
--- a/openbsc/src/mgcp/mgcp_protocol.c
+++ b/openbsc/src/mgcp/mgcp_protocol.c
@@ -80,11 +80,6 @@
 	}
 
 
-struct mgcp_msg_ptr {
-	unsigned int start;
-	unsigned int length;
-};
-
 struct mgcp_request {
 	char *name;
 	struct msgb *(*handle_request) (struct mgcp_config *cfg, struct msgb *msg);
@@ -98,6 +93,7 @@
 static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg);
 static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg);
 static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg);
+static struct msgb *handle_rsip(struct mgcp_config *cfg, struct msgb *msg);
 
 static int generate_call_id(struct mgcp_config *cfg)
 {
@@ -119,12 +115,6 @@
 	return cfg->last_call_id;
 }
 
-/* FIXIME/TODO: need to have a list of pending transactions and check that */
-static unsigned int generate_transaction_id()
-{
-	return abs(rand());
-}
-
 /*
  * array of function pointers for handling various
  * messages. In the future this might be binary sorted
@@ -135,6 +125,9 @@
 	MGCP_REQUEST("CRCX", handle_create_con, "CreateConnection")
 	MGCP_REQUEST("DLCX", handle_delete_con, "DeleteConnection")
 	MGCP_REQUEST("MDCX", handle_modify_con, "ModifiyConnection")
+
+	/* SPEC extension */
+	MGCP_REQUEST("RSIP", handle_rsip, "ReSetInProgress")
 };
 
 static struct msgb *mgcp_msgb_alloc(void)
@@ -194,23 +187,6 @@
 	return mgcp_create_response_with_data(200, msg, trans_id, sdp_record);
 }
 
-/* send a static record */
-struct msgb *mgcp_create_rsip(void)
-{
-	struct msgb *msg;
-	int len;
-
-	msg = mgcp_msgb_alloc();
-	if (!msg)
-		return NULL;
-
-	len = snprintf((char *) msg->data, 2048,
-			"RSIP %u *@mgw MGCP 1.0\n"
-			"RM: restart\n", generate_transaction_id());
-	msg->l2h = msgb_put(msg, len);
-	return msg;
-}
-
 /*
  * handle incoming messages:
  *   - this can be a command (four letters, space, transaction id)
@@ -221,25 +197,25 @@
         int code;
 	struct msgb *resp = NULL;
 
-	if (msg->len < 4) {
+	if (msgb_l2len(msg) < 4) {
 		LOGP(DMGCP, LOGL_ERROR, "mgs too short: %d\n", msg->len);
 		return NULL;
 	}
 
         /* attempt to treat it as a response */
-        if (sscanf((const char *)&msg->data[0], "%3d %*s", &code) == 1) {
+        if (sscanf((const char *)&msg->l2h[0], "%3d %*s", &code) == 1) {
 		LOGP(DMGCP, LOGL_DEBUG, "Response: Code: %d\n", code);
 	} else {
 		int i, handled = 0;
 		msg->l3h = &msg->l2h[4];
 		for (i = 0; i < ARRAY_SIZE(mgcp_requests); ++i)
-			if (strncmp(mgcp_requests[i].name, (const char *) &msg->data[0], 4) == 0) {
+			if (strncmp(mgcp_requests[i].name, (const char *) &msg->l2h[0], 4) == 0) {
 				handled = 1;
 				resp = mgcp_requests[i].handle_request(cfg, msg);
 				break;
 			}
 		if (!handled) {
-			LOGP(DMGCP, LOGL_NOTICE, "MSG with type: '%.4s' not handled\n", &msg->data[0]);
+			LOGP(DMGCP, LOGL_NOTICE, "MSG with type: '%.4s' not handled\n", &msg->l2h[0]);
 		}
 	}
 
@@ -296,9 +272,9 @@
 	return &cfg->endpoints[gw];
 }
 
-static int analyze_header(struct mgcp_config *cfg, struct msgb *msg,
-			  struct mgcp_msg_ptr *ptr, int size,
-			  const char **transaction_id, struct mgcp_endpoint **endp)
+int mgcp_analyze_header(struct mgcp_config *cfg, struct msgb *msg,
+			struct mgcp_msg_ptr *ptr, int size,
+			const char **transaction_id, struct mgcp_endpoint **endp)
 {
 	int found;
 
@@ -334,8 +310,11 @@
 	}
 
 	*transaction_id = (const char *)&msg->l3h[ptr[0].start];
-	*endp = find_endpoint(cfg, (const char *)&msg->l3h[ptr[1].start]);
-	return *endp == NULL;
+	if (endp) {
+		*endp = find_endpoint(cfg, (const char *)&msg->l3h[ptr[1].start]);
+		return *endp == NULL;
+	}
+	return 0;
 }
 
 static int verify_call_id(const struct mgcp_endpoint *endp,
@@ -369,7 +348,7 @@
 	const char *trans_id;
 	struct mgcp_endpoint *endp;
 
-	found = analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
+	found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
 	if (found != 0)
 	    response = 500;
 	else
@@ -402,13 +381,19 @@
 	int error_code = 500;
 	int port;
 
-	found = analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
+	found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
 	if (found != 0)
 		return create_response(500, "CRCX", trans_id);
 
 	if (endp->ci != CI_UNUSED) {
-		LOGP(DMGCP, LOGL_ERROR, "Endpoint is already used. 0x%x\n", ENDPOINT_NUMBER(endp));
-		return create_response(500, "CRCX", trans_id);
+		if (cfg->force_realloc) {
+			LOGP(DMGCP, LOGL_NOTICE, "Endpoint 0x%x already allocated. Forcing realloc.\n",
+			    ENDPOINT_NUMBER(endp));
+		} else {
+			LOGP(DMGCP, LOGL_ERROR, "Endpoint is already used. 0x%x\n",
+			     ENDPOINT_NUMBER(endp));
+			return create_response(500, "CRCX", trans_id);
+		}
 	}
 
 	/* parse CallID C: and LocalParameters L: */
@@ -501,7 +486,7 @@
 	struct mgcp_endpoint *endp;
 	int error_code = 500;
 
-	found = analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
+	found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
 	if (found != 0)
 		return create_response(error_code, "MDCX", trans_id);
 
@@ -614,7 +599,7 @@
 	struct mgcp_endpoint *endp;
 	int error_code = 500;
 
-	found = analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
+	found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
 	if (found != 0)
 		return create_response(error_code, "DLCX", trans_id);
 
@@ -678,6 +663,13 @@
 	return create_response(error_code, "DLCX", trans_id);
 }
 
+static struct msgb *handle_rsip(struct mgcp_config *cfg, struct msgb *msg)
+{
+	if (cfg->reset_cb)
+		cfg->reset_cb(cfg);
+	return NULL;
+}
+
 struct mgcp_config *mgcp_config_alloc(void)
 {
 	struct mgcp_config *cfg;
@@ -722,7 +714,7 @@
 
 void mgcp_free_endp(struct mgcp_endpoint *endp)
 {
-	LOGP(DMGCP, LOGL_NOTICE, "Deleting endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp));
+	LOGP(DMGCP, LOGL_DEBUG, "Deleting endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp));
 	endp->ci= CI_UNUSED;
 
 	if (endp->callid) {
@@ -732,7 +724,7 @@
 
 	if (endp->local_options) {
 		talloc_free(endp->local_options);
-		endp->callid = NULL;
+		endp->local_options = NULL;
 	}
 
 	if (!endp->cfg->early_bind) {
@@ -742,4 +734,7 @@
 
 	endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0;
 	endp->net_payload_type = endp->bts_payload_type = -1;
+	endp->in_bts = endp->in_remote = 0;
+	memset(&endp->remote, 0, sizeof(endp->remote));
+	memset(&endp->bts, 0, sizeof(endp->bts));
 }
diff --git a/openbsc/src/mgcp/mgcp_vty.c b/openbsc/src/mgcp/mgcp_vty.c
index f13b3cf..af762c5 100644
--- a/openbsc/src/mgcp/mgcp_vty.c
+++ b/openbsc/src/mgcp/mgcp_vty.c
@@ -63,6 +63,8 @@
 		vty_out(vty, " forward audio ip %s%s", g_cfg->forward_ip, VTY_NEWLINE);
 	if (g_cfg->forward_port != 0)
 		vty_out(vty, " forward audio port %d%s", g_cfg->forward_port, VTY_NEWLINE);
+	if (g_cfg->call_agent_addr)
+		vty_out(vty, " call agent ip %s%s", g_cfg->call_agent_addr, VTY_NEWLINE);
 
 	return CMD_SUCCESS;
 }
@@ -75,10 +77,12 @@
 	vty_out(vty, "MGCP is up and running with %u endpoints:%s", g_cfg->number_endpoints - 1, VTY_NEWLINE);
 	for (i = 1; i < g_cfg->number_endpoints; ++i) {
 		struct mgcp_endpoint *endp = &g_cfg->endpoints[i];
-		vty_out(vty, " Endpoint 0x%.2x: CI: %d net: %u/%u bts: %u/%u%s",
+		vty_out(vty, " Endpoint 0x%.2x: CI: %d net: %u/%u bts: %u/%u on %s traffic in :%u/%u%s",
 			i, endp->ci,
 			ntohs(endp->net_rtp), ntohs(endp->net_rtcp),
-			ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp), VTY_NEWLINE);
+			ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp),
+			inet_ntoa(endp->bts), endp->in_bts, endp->in_remote,
+			VTY_NEWLINE);
 	}
 
 	return CMD_SUCCESS;
@@ -237,6 +241,17 @@
 	return CMD_SUCCESS;
 }
 
+DEFUN(cfg_mgcp_agent_addr,
+      cfg_mgcp_agent_addr_cmd,
+      "call agent ip IP",
+      "Set the address of the call agent.")
+{
+	if (g_cfg->call_agent_addr)
+		talloc_free(g_cfg->call_agent_addr);
+	g_cfg->call_agent_addr = talloc_strdup(g_cfg, argv[0]);
+	return CMD_SUCCESS;
+}
+
 int mgcp_vty_init(void)
 {
 	install_element(VIEW_NODE, &show_mgcp_cmd);
@@ -256,6 +271,7 @@
 	install_element(MGCP_NODE, &cfg_mgcp_number_endp_cmd);
 	install_element(MGCP_NODE, &cfg_mgcp_forward_ip_cmd);
 	install_element(MGCP_NODE, &cfg_mgcp_forward_port_cmd);
+	install_element(MGCP_NODE, &cfg_mgcp_agent_addr_cmd);
 	return 0;
 }
 
@@ -274,6 +290,11 @@
 	if (!g_cfg->bts_ip)
 		fprintf(stderr, "No BTS ip address specified. This will allow everyone to connect.\n");
 
+	if (!g_cfg->source_addr) {
+		fprintf(stderr, "You need to specify a bind address.\n");
+		return -1;
+	}
+
 	if (mgcp_endpoints_allocate(g_cfg) != 0) {
 		fprintf(stderr, "Failed to allocate endpoints: %d. Quitting.\n", g_cfg->number_endpoints);
 		return -1;
@@ -327,13 +348,3 @@
 	return !!g_cfg->forward_ip;
 }
 
-struct gsm_network;
-int bsc_vty_init(struct gsm_network *dummy)
-{
-	cmd_init(1);
-	vty_init();
-
-        mgcp_vty_init();
-	return 0;
-}
-