nat: Keep track of both sides of the connection

On a CC message we will need to remeber where the source local
reference of the network belonged so we can properly identify
the connection when receiving UDT messages.
diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h
index 2f2b8c9..5f730fe 100644
--- a/openbsc/include/openbsc/bsc_nat.h
+++ b/openbsc/include/openbsc/bsc_nat.h
@@ -102,6 +102,7 @@
 
 	struct sccp_source_reference real_ref;
 	struct sccp_source_reference patched_ref;
+	struct sccp_source_reference remote_ref;
 };
 
 /**
@@ -154,6 +155,7 @@
  * SCCP patching and handling
  */
 int create_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed);
+int update_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed);
 void remove_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed);
 struct bsc_connection *patch_sccp_src_ref_to_bsc(struct msgb *, struct bsc_nat_parsed *, struct bsc_nat *);
 struct bsc_connection *patch_sccp_src_ref_to_msc(struct msgb *, struct bsc_nat_parsed *, struct bsc_nat *);
diff --git a/openbsc/src/nat/bsc_nat.c b/openbsc/src/nat/bsc_nat.c
index 65fc10b..cafca83 100644
--- a/openbsc/src/nat/bsc_nat.c
+++ b/openbsc/src/nat/bsc_nat.c
@@ -191,7 +191,11 @@
 		case SCCP_MSG_TYPE_RLSD:
 		case SCCP_MSG_TYPE_CREF:
 		case SCCP_MSG_TYPE_DT1:
+			bsc = patch_sccp_src_ref_to_bsc(msg, parsed, nat);
+			break;
 		case SCCP_MSG_TYPE_CC:
+			if (update_sccp_src_ref(bsc, msg, parsed) != 0)
+				goto exit;
 			bsc = patch_sccp_src_ref_to_bsc(msg, parsed, nat);
 			break;
 		case SCCP_MSG_TYPE_RLC:
diff --git a/openbsc/src/nat/bsc_sccp.c b/openbsc/src/nat/bsc_sccp.c
index 226e2e0..e29dc9b 100644
--- a/openbsc/src/nat/bsc_sccp.c
+++ b/openbsc/src/nat/bsc_sccp.c
@@ -103,6 +103,34 @@
 	return 0;
 }
 
+int update_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed)
+{
+	struct sccp_connections *conn;
+
+	if (!parsed->dest_local_ref || !parsed->src_local_ref) {
+		LOGP(DNAT, LOGL_ERROR, "CC MSG should contain both local and dest address.\n");
+		return -1;
+	}
+
+	llist_for_each_entry(conn, &bsc->nat->sccp_connections, list_entry) {
+		if (conn->bsc != bsc)
+			continue;
+
+		if (memcmp(parsed->dest_local_ref,
+			   &conn->patched_ref, sizeof(conn->patched_ref)) != 0)
+			continue;
+
+		conn->remote_ref = *parsed->src_local_ref;
+		LOGP(DNAT, LOGL_DEBUG, "Updating 0x%x to remote 0x%x on 0x%p\n",
+		     sccp_src_ref_to_int(&conn->patched_ref),
+		     sccp_src_ref_to_int(&conn->remote_ref), bsc);
+		return 0;
+	}
+
+	LOGP(DNAT, LOGL_ERROR, "Referenced connection not found on BSC: 0x%p\n", bsc);
+	return -1;
+}
+
 void remove_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed)
 {
 	struct sccp_connections *conn;