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.
diff --git a/openbsc/src/nat/bsc_nat.c b/openbsc/src/nat/bsc_nat.c
index c7d97aa..e71ab0f 100644
--- a/openbsc/src/nat/bsc_nat.c
+++ b/openbsc/src/nat/bsc_nat.c
@@ -303,6 +303,63 @@
 	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 @@
 					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;