nat: Handle CRCX/MDCX/DLCX at the nat

* Forward a rewritten msg to the BSS. We change the IP and port
  to point to the NAT instead of the core network. We also keep
  track of the BSC and the transacition id.
* Handle the case where we have not found a SCCP connection and
  need to send a response ourselves.
diff --git a/openbsc/src/nat/bsc_mgcp_utils.c b/openbsc/src/nat/bsc_mgcp_utils.c
index 3639a7b..24f66a1 100644
--- a/openbsc/src/nat/bsc_mgcp_utils.c
+++ b/openbsc/src/nat/bsc_mgcp_utils.c
@@ -26,6 +26,8 @@
 #include <openbsc/mgcp.h>
 #include <openbsc/mgcp_internal.h>
 
+#include <osmocore/talloc.h>
+
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
@@ -70,12 +72,23 @@
 	con->bsc_timeslot = -1;
 }
 
+void bsc_mgcp_free_endpoint(struct bsc_nat *nat, int i)
+{
+	if (nat->bsc_endpoints[i].transaction_id) {
+		talloc_free(nat->bsc_endpoints[i].transaction_id);
+		nat->bsc_endpoints[i].transaction_id = NULL;
+	}
+
+	nat->bsc_endpoints[i].bsc = NULL;
+	mgcp_free_endp(&nat->mgcp_cfg->endpoints[i]);
+}
+
 void bsc_mgcp_free_endpoints(struct bsc_nat *nat)
 {
 	int i;
 
 	for (i = 1; i < nat->mgcp_cfg->number_endpoints; ++i)
-		mgcp_free_endp(&nat->mgcp_cfg->endpoints[i]);
+		bsc_mgcp_free_endpoint(nat, i);
 }
 
 struct bsc_connection *bsc_mgcp_find_con(struct bsc_nat *nat, int endpoint)
@@ -95,6 +108,71 @@
 	return NULL;
 }
 
+int bsc_mgcp_policy_cb(struct mgcp_config *cfg, int endpoint, int state, const char *transaction_id)
+{
+	struct bsc_nat *nat;
+	struct bsc_endpoint *bsc_endp;
+	struct bsc_connection *bsc_con;
+	struct mgcp_endpoint *mgcp_endp;
+	struct msgb *bsc_msg;
+
+	nat = cfg->data;
+	bsc_endp = &nat->bsc_endpoints[endpoint];
+	mgcp_endp = &nat->mgcp_cfg->endpoints[endpoint];
+
+	bsc_con = bsc_mgcp_find_con(nat, endpoint);
+
+	if (!bsc_con) {
+		LOGP(DMGCP, LOGL_ERROR, "Did not find BSC for a new connection on 0x%x for %d\n", endpoint, state);
+
+		switch (state) {
+		case MGCP_ENDP_CRCX:
+			return MGCP_POLICY_REJECT;
+			break;
+		case MGCP_ENDP_DLCX:
+			return MGCP_POLICY_CONT;
+			break;
+		case MGCP_ENDP_MDCX:
+			return MGCP_POLICY_CONT;
+			break;
+		default:
+			LOGP(DMGCP, LOGL_FATAL, "Unhandled state: %d\n", state);
+			return MGCP_POLICY_CONT;
+			break;
+		}
+	}
+
+	if (bsc_endp->transaction_id) {
+		LOGP(DMGCP, LOGL_ERROR, "One transaction with id '%s' on 0x%x\n",
+		     bsc_endp->transaction_id, endpoint);
+		talloc_free(bsc_endp->transaction_id);
+	}
+
+	bsc_endp->transaction_id = talloc_strdup(bsc_endp, transaction_id);
+	bsc_endp->bsc = bsc_con;
+
+	/* we need to update some bits */
+	if (state == MGCP_ENDP_CRCX) {
+		struct sockaddr_in sock;
+		socklen_t len = sizeof(sock);
+		if (getpeername(nat->mgcp_queue.bfd.fd, (struct sockaddr *) &sock, &len) != 0) {
+			LOGP(DMGCP, LOGL_ERROR, "Can not get the peername...\n");
+		} else {
+			mgcp_endp->bts = sock.sin_addr;
+		}
+	}
+
+	/* we need to generate a new and patched message */
+	bsc_msg = bsc_mgcp_rewrite(nat->mgcp_msg, nat->mgcp_cfg->source_addr, mgcp_endp->rtp_port);
+	if (!bsc_msg) {
+		LOGP(DMGCP, LOGL_ERROR, "Failed to patch the msg.\n");
+		return MGCP_POLICY_CONT;
+	}
+
+	bsc_write_mgcp_msg(bsc_con, bsc_msg);
+	return MGCP_POLICY_DEFER;
+}
+
 /* we need to replace some strings... */
 struct msgb *bsc_mgcp_rewrite(struct msgb *input, const char *ip, int port)
 {
@@ -177,9 +255,11 @@
 	}
 
 	nat = fd->data;
+	nat->mgcp_msg = msg;
 	msg->l2h = msgb_put(msg, rc);
 	resp = mgcp_handle_message(nat->mgcp_cfg, msg);
 	msgb_free(msg);
+	nat->mgcp_msg = NULL;
 
 	/* we do have a direct answer... e.g. AUEP */
 	if (resp) {
@@ -216,6 +296,11 @@
 		return -1;
 	}
 
+	if (nat->mgcp_cfg->bts_ip) {
+		LOGP(DMGCP, LOGL_ERROR, "Do not set the BTS ip for the nat.\n");
+		return -1;
+	}
+
 	nat->mgcp_queue.bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
 	if (nat->mgcp_queue.bfd.fd < 0) {
 		LOGP(DMGCP, LOGL_ERROR, "Failed to create MGCP socket. errno: %d\n", errno);
@@ -259,5 +344,12 @@
 		return -1;
 	}
 
+	/* some more MGCP config handling */
+	nat->mgcp_cfg->data = nat;
+	nat->mgcp_cfg->policy_cb = bsc_mgcp_policy_cb;
+	nat->bsc_endpoints = talloc_zero_array(nat,
+					       struct bsc_endpoint,
+					       nat->mgcp_cfg->number_endpoints + 1);
+
 	return 0;
 }