aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <zecke@selfish.org>2010-05-14 08:14:09 +0800
committerHolger Hans Peter Freyther <zecke@selfish.org>2010-06-15 20:24:18 +0800
commit290ed9a98c4c64bc2466ca7fd86e7d1fb1da3e11 (patch)
treec98fe5b2d2e49b989d4334c8c6441a74105978ef
parent0c08db17bf74779d4f4bb89c379b71166bd87249 (diff)
nat: Add code to parse the SCCP optional data.
First we have the Complete Layer3 Information, then we have the IE for the Layer3 information, then the GSM48 hdr, then the actual content with data. Right now we are parsing the LU but we are not filtering anything yet.
-rw-r--r--openbsc/src/nat/bsc_nat_utils.c79
1 files changed, 76 insertions, 3 deletions
diff --git a/openbsc/src/nat/bsc_nat_utils.c b/openbsc/src/nat/bsc_nat_utils.c
index 0c79fff1b..6baa952e6 100644
--- a/openbsc/src/nat/bsc_nat_utils.c
+++ b/openbsc/src/nat/bsc_nat_utils.c
@@ -193,9 +193,82 @@ int bsc_write(struct bsc_connection *bsc, struct msgb *msg, int proto)
return 0;
}
-/* Filter out CM Service Requests... */
-int bsc_nat_filter_sccp_cr(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed)
+
+static int _cr_check_loc_upd(struct bsc_connection *bsc, uint8_t *data, unsigned int length)
{
- /* the data we want to look at is optional. We want to have it here... */
+ u_int8_t mi_type;
+ struct gsm48_loc_upd_req *lu;
+ char mi_string[GSM48_MI_SIZE];
+
+ if (sizeof(*lu) < length) {
+ LOGP(DNAT, LOGL_ERROR, "Location updating request does not fit.\n");
+ return -1;
+ }
+
+ lu = (struct gsm48_loc_upd_req *) data;
+ mi_type = lu->mi[0] & GSM_MI_TYPE_MASK;
+
+ /*
+ * We can only deal with the IMSI. This will fail for a phone that
+ * will send the TMSI of a previous network to us.
+ */
+ if (mi_type != GSM_MI_TYPE_IMSI)
+ return 0;
+
+ gsm48_mi_to_string(mi_string, sizeof(mi_string), lu->mi, lu->mi_len);
+
+ /*
+ * Now apply blacklist/whitelist
+ */
+
return 0;
}
+
+
+/* Filter out CR data... */
+int bsc_nat_filter_sccp_cr(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed)
+{
+ struct tlv_parsed tp;
+ struct gsm48_hdr *hdr48;
+ int hdr48_len;
+ int len;
+
+ if (parsed->gsm_type != BSS_MAP_MSG_COMPLETE_LAYER_3) {
+ LOGP(DNAT, LOGL_ERROR,
+ "Rejecting CR message due wrong GSM Type %d\n", parsed->gsm_type);
+ return -1;
+ }
+
+ /* the parsed has had some basic l3 length check */
+ len = msg->l3h[1];
+ if (msgb_l3len(msg) - 3 < len) {
+ LOGP(DNAT, LOGL_ERROR,
+ "The CR Data has not enough space...\n");
+ return -1;
+ }
+
+ msg->l4h = &msg->l3h[3];
+ len -= 1;
+
+ tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h, len, 0, 0);
+
+ if (!TLVP_PRESENT(&tp, GSM0808_IE_LAYER_3_INFORMATION)) {
+ LOGP(DNAT, LOGL_ERROR, "CR Data does not contain layer3 information.\n");
+ return -1;
+ }
+
+ hdr48_len = TLVP_LEN(&tp, GSM0808_IE_LAYER_3_INFORMATION);
+
+ if (hdr48_len < sizeof(*hdr48)) {
+ LOGP(DNAT, LOGL_ERROR, "GSM48 header does not fit.\n");
+ return -1;
+ }
+
+ hdr48 = (struct gsm48_hdr *) TLVP_VAL(&tp, GSM0808_IE_LAYER_3_INFORMATION);
+
+ if (hdr48->msg_type == GSM48_MT_MM_LOC_UPD_REQUEST) {
+ return _cr_check_loc_upd(bsc, &hdr48->data[0], hdr48_len - sizeof(*hdr48));
+ } else {
+ return 0;
+ }
+}