aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <zecke@selfish.org>2010-09-15 07:43:59 +0800
committerHolger Hans Peter Freyther <zecke@selfish.org>2010-09-15 18:58:36 +0800
commitac2763b47e49e99ea6b0d2bcf2d55fafc0721b50 (patch)
tree5c342d741d8a83315e9285222958f57ff14abada
parent11ebe1bf05138085842814c9d9d5d379806031c5 (diff)
nat: Attempt to disconnect a connection when IMSI filtering happens
Attempt to disconnect the connection and make both sides happy about this. Right now it only handles the LU and should be extended to the CM Service Request.
-rw-r--r--openbsc/src/nat/bsc_nat.c64
1 files changed, 60 insertions, 4 deletions
diff --git a/openbsc/src/nat/bsc_nat.c b/openbsc/src/nat/bsc_nat.c
index c7d97aa45..e71ab0fcf 100644
--- a/openbsc/src/nat/bsc_nat.c
+++ b/openbsc/src/nat/bsc_nat.c
@@ -303,6 +303,63 @@ static void bsc_send_data(struct bsc_connection *bsc, const uint8_t *data, unsig
bsc_write(bsc, msg, proto);
}
+/*
+ * Release an established connection. We will have to release it to the BSC
+ * and to the network and we do it the following way.
+ * 1.) Give up on the MSC side
+ * 1.1) Send a RLSD message, it is a bit non standard but should work, we
+ * ignore the RLC... we might complain about it. Other options would
+ * be to send a Release Request, handle the Release Complete..
+ * 1.2) Mark the data structure to be con_local and wait for 2nd
+ *
+ * 2.) Give up on the BSC side
+ * 2.1) Depending on the con type reject the service, or just close it
+ */
+static void bsc_send_con_release(struct bsc_connection *bsc, struct sccp_connections *con)
+{
+ struct msgb *rlsd;
+ /* 1. release the network */
+ rlsd = sccp_create_rlsd(&con->patched_ref, &con->remote_ref,
+ SCCP_RELEASE_CAUSE_END_USER_ORIGINATED);
+ if (!rlsd)
+ LOGP(DNAT, LOGL_ERROR, "Failed to create RLSD message.\n");
+ else {
+ ipaccess_prepend_header(rlsd, IPAC_PROTO_SCCP);
+ queue_for_msc(con->msc_con, rlsd);
+ }
+ con->con_local = 1;
+
+ /* 2. release the BSC side */
+ if (con->con_type == NAT_CON_TYPE_LU) {
+ struct msgb *payload, *udt;
+ payload = gsm48_create_loc_upd_rej(GSM48_REJECT_PLMN_NOT_ALLOWED);
+
+ if (payload) {
+ gsm0808_prepend_dtap_header(payload, 0);
+ udt = sccp_create_dt1(&con->real_ref, payload->data, payload->len);
+ if (udt)
+ bsc_write(bsc, udt, IPAC_PROTO_SCCP);
+ else
+ LOGP(DNAT, LOGL_ERROR, "Failed to create DT1\n");
+
+ msgb_free(payload);
+ } else {
+ LOGP(DNAT, LOGL_ERROR, "Failed to allocate LU Reject.\n");
+ }
+ }
+
+ rlsd = sccp_create_rlsd(&con->remote_ref, &con->real_ref,
+ SCCP_RELEASE_CAUSE_END_USER_ORIGINATED);
+ if (!rlsd) {
+ LOGP(DNAT, LOGL_ERROR, "Failed to allocate RLSD for the BSC.\n");
+ sccp_connection_destroy(con);
+ return;
+ }
+
+ con->con_type = NAT_CON_TYPE_LOCAL_REJECT;
+ bsc_write(bsc, rlsd, IPAC_PROTO_SCCP);
+}
+
static void bsc_send_con_refuse(struct bsc_connection *bsc,
struct bsc_nat_parsed *parsed, int con_type)
{
@@ -737,10 +794,9 @@ static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg)
con_msc = con->msc_con;
con_filter = con->con_local;
} else {
- LOGP(DNAT, LOGL_ERROR, "Should drop the connection.\n");
- con_bsc = con->bsc;
- con_msc = con->msc_con;
- con_filter = con->con_local;
+ bsc_send_con_release(bsc, con);
+ con = NULL;
+ goto exit2;
}
}
break;