nat: Extract the LAC/CI from the Complete Layer3 Information

Find the Cell Identifier from the Complete Layer3 Information and
store it for future reference. We could begin to verify that the
LAC/CI used really belongs to the BSC.
diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat.c b/openbsc/src/osmo-bsc_nat/bsc_nat.c
index 21f5287..0496802 100644
--- a/openbsc/src/osmo-bsc_nat/bsc_nat.c
+++ b/openbsc/src/osmo-bsc_nat/bsc_nat.c
@@ -1,8 +1,8 @@
 /* BSC Multiplexer/NAT */
 
 /*
- * (C) 2010-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2010-2012 by On-Waves
+ * (C) 2010-2013 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * (C) 2010-2013 by On-Waves
  * (C) 2009 by Harald Welte <laforge@gnumonks.org>
  * All Rights Reserved
  *
@@ -1056,6 +1056,7 @@
 			con_msc = con->msc_con;
 			con->con_type = con_type;
 			con->imsi_checked = filter;
+			bsc_nat_extract_lac(bsc, con, parsed, msg);
 			if (imsi)
 				con->imsi = talloc_steal(con, imsi);
 			imsi = NULL;
diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c b/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c
index b4c87d0..45c224c 100644
--- a/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c
+++ b/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c
@@ -502,3 +502,65 @@
 	return rc;
 }
 
+static void extract_lac(const uint8_t *data, uint16_t *lac, uint16_t *ci)
+{
+	memcpy(lac, &data[0], sizeof(*lac));
+	memcpy(ci, &data[2], sizeof(*ci));
+
+	*lac = ntohs(*lac);
+	*ci = ntohs(*ci);
+}
+
+int bsc_nat_extract_lac(struct bsc_connection *bsc,
+			struct nat_sccp_connection *con,
+			struct bsc_nat_parsed *parsed, struct msgb *msg)
+{
+	int data_length;
+	const uint8_t *data;
+	struct tlv_parsed tp;
+	uint16_t lac, ci;
+
+	if (parsed->gsm_type != BSS_MAP_MSG_COMPLETE_LAYER_3) {
+		LOGP(DNAT, LOGL_ERROR, "Can only extract LAC from Complete Layer3\n");
+		return -1;
+	}
+
+	if (!msg->l3h || msgb_l3len(msg) < 3) {
+		LOGP(DNAT, LOGL_ERROR, "Complete Layer3 mssage is too short.\n");
+		return -1;
+	}
+
+	tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 3, msgb_l3len(msg) - 3, 0, 0);
+	if (!TLVP_PRESENT(&tp, GSM0808_IE_CELL_IDENTIFIER)) {
+		LOGP(DNAT, LOGL_ERROR, "No CellIdentifier List inside paging msg.\n");
+		return -2;
+	}
+
+	data_length = TLVP_LEN(&tp, GSM0808_IE_CELL_IDENTIFIER);
+	data = TLVP_VAL(&tp, GSM0808_IE_CELL_IDENTIFIER);
+
+	/* Attemt to get the LAC/CI from it */
+	if (data[0] == CELL_IDENT_WHOLE_GLOBAL) {
+		if (data_length != 8) {
+			LOGP(DNAT, LOGL_ERROR,
+				"Ident too short: %d\n", data_length);
+			return -3;
+		}
+		extract_lac(&data[1 + 3], &lac, &ci);
+	} else if (data[0] == CELL_IDENT_LAC_AND_CI) {
+		if (data_length != 5) {
+			LOGP(DNAT, LOGL_ERROR,
+				"Ident too short: %d\n", data_length);
+			return -3;
+		}
+		extract_lac(&data[1], &lac, &ci);
+	} else {
+		LOGP(DNAT, LOGL_ERROR,
+			"Unhandled cell identifier: %d\n", data[0]);
+		return -1;
+	}
+
+	con->lac = lac;
+	con->ci = ci;
+	return 0;
+}