nat: Introduce reject cause to bsc_nat_acc_lst_entry

The filtering architecture already allowed to specify a reject
reason but this has not been used for the access-lists. Extend
the access-list to include a reject reason and extend the test
case to honor it.
diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h
index 150979b..fe8e521 100644
--- a/openbsc/include/openbsc/bsc_nat.h
+++ b/openbsc/include/openbsc/bsc_nat.h
@@ -247,6 +247,10 @@
 	regex_t imsi_allow_re;
 	char *imsi_deny;
 	regex_t imsi_deny_re;
+
+	/* reject reasons for the access lists */
+	int cm_reject_cause;
+	int lu_reject_cause;
 };
 
 /**
diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_filter.c b/openbsc/src/osmo-bsc_nat/bsc_nat_filter.c
index 8ccc262..d29ea9c 100644
--- a/openbsc/src/osmo-bsc_nat/bsc_nat_filter.c
+++ b/openbsc/src/osmo-bsc_nat/bsc_nat_filter.c
@@ -122,15 +122,19 @@
 }
 
 
-static int lst_check_deny(struct bsc_nat_acc_lst *lst, const char *mi_string)
+static int lst_check_deny(struct bsc_nat_acc_lst *lst, const char *mi_string,
+			int *cm_cause, int *lu_cause)
 {
 	struct bsc_nat_acc_lst_entry *entry;
 
 	llist_for_each_entry(entry, &lst->fltr_list, list) {
 		if (!entry->imsi_deny)
 			continue;
-		if (regexec(&entry->imsi_deny_re, mi_string, 0, NULL, 0) == 0)
+		if (regexec(&entry->imsi_deny_re, mi_string, 0, NULL, 0) == 0) {
+			*cm_cause = entry->cm_reject_cause;
+			*lu_cause = entry->lu_reject_cause;
 			return 0;
+		}
 	}
 
 	return 1;
@@ -173,10 +177,12 @@
 			return 1;
 
 		/* 3. BSC deny */
-		if (lst_check_deny(bsc_lst, imsi) == 0) {
+		if (lst_check_deny(bsc_lst, imsi, &cm, &lu) == 0) {
 			LOGP(DNAT, LOGL_ERROR,
 			     "Filtering %s by imsi_deny on bsc nr: %d.\n", imsi, bsc->cfg->nr);
 			rate_ctr_inc(&bsc_lst->stats->ctr[ACC_LIST_BSC_FILTER]);
+			cause->cm_reject_cause = cm;
+			cause->lu_reject_cause = lu;
 			return -2;
 		}
 
@@ -184,10 +190,12 @@
 
 	/* 4. NAT deny */
 	if (nat_lst) {
-		if (lst_check_deny(nat_lst, imsi) == 0) {
+		if (lst_check_deny(nat_lst, imsi, &cm, &lu) == 0) {
 			LOGP(DNAT, LOGL_ERROR,
 			     "Filtering %s by nat imsi_deny on bsc nr: %d.\n", imsi, bsc->cfg->nr);
 			rate_ctr_inc(&nat_lst->stats->ctr[ACC_LIST_NAT_FILTER]);
+			cause->cm_reject_cause = cm;
+			cause->lu_reject_cause = lu;
 			return -3;
 		}
 	}
diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c b/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c
index bc8c4c1..236a0fb 100644
--- a/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c
+++ b/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c
@@ -468,6 +468,8 @@
 	if (!entry)
 		return NULL;
 
+	entry->cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED;
+	entry->lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED;
 	llist_add_tail(&entry->list, &lst->fltr_list);
 	return entry;
 }
diff --git a/openbsc/tests/bsc-nat/bsc_nat_test.c b/openbsc/tests/bsc-nat/bsc_nat_test.c
index a121c8a..bed5b80 100644
--- a/openbsc/tests/bsc-nat/bsc_nat_test.c
+++ b/openbsc/tests/bsc-nat/bsc_nat_test.c
@@ -696,6 +696,12 @@
 	const char *bsc_imsi_allow;
 	const char *bsc_imsi_deny;
 	const char *nat_imsi_deny;
+	int nat_cm_reject_cause;
+	int nat_lu_reject_cause;
+	int bsc_cm_reject_cause;
+	int bsc_lu_reject_cause;
+	int want_cm_reject_cause;
+	int want_lu_reject_cause;
 };
 
 static struct cr_filter cr_filter[] = {
@@ -704,18 +710,36 @@
 		.length = sizeof(bssmap_cr),
 		.result = 1,
 		.contype = NAT_CON_TYPE_CM_SERV_REQ,
+		.nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.bsc_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.want_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.want_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
 	},
 	{
 		.data = bss_lu,
 		.length = sizeof(bss_lu),
 		.result = 1,
 		.contype = NAT_CON_TYPE_LU,
+		.nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.bsc_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.want_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.want_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
 	},
 	{
 		.data = pag_resp,
 		.length = sizeof(pag_resp),
 		.result = 1,
 		.contype = NAT_CON_TYPE_PAG_RESP,
+		.nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.bsc_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.want_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.want_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
 	},
 	{
 		/* nat deny is before blank/null BSC */
@@ -724,6 +748,12 @@
 		.result = -3,
 		.nat_imsi_deny = "[0-9]*",
 		.contype = NAT_CON_TYPE_LU,
+		.nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.bsc_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.want_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.want_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
 	},
 	{
 		/* BSC allow is before NAT deny */
@@ -733,6 +763,12 @@
 		.nat_imsi_deny = "[0-9]*",
 		.bsc_imsi_allow = "2440[0-9]*",
 		.contype = NAT_CON_TYPE_LU,
+		.nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.bsc_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.want_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.want_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
 	},
 	{
 		/* BSC allow is before NAT deny */
@@ -742,6 +778,12 @@
 		.bsc_imsi_allow = "[0-9]*",
 		.nat_imsi_deny = "[0-9]*",
 		.contype = NAT_CON_TYPE_LU,
+		.nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.bsc_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.want_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.want_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
 	},
 	{
 		/* filter as deny is first */
@@ -752,6 +794,12 @@
 		.bsc_imsi_allow = "[0-9]*",
 		.nat_imsi_deny = "[0-9]*",
 		.contype = NAT_CON_TYPE_LU,
+		.nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.bsc_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.want_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.want_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
 	},
 	{
 		/* deny by nat rule */
@@ -761,6 +809,27 @@
 		.bsc_imsi_deny = "000[0-9]*",
 		.nat_imsi_deny = "[0-9]*",
 		.contype = NAT_CON_TYPE_LU,
+		.nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.bsc_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.want_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.want_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+	},
+	{
+		/* deny by nat rule */
+		.data = bss_lu,
+		.length = sizeof(bss_lu),
+		.result = -3,
+		.bsc_imsi_deny = "000[0-9]*",
+		.nat_imsi_deny = "[0-9]*",
+		.contype = NAT_CON_TYPE_LU,
+		.nat_cm_reject_cause = 0x23,
+		.nat_lu_reject_cause = 0x42,
+		.bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.bsc_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.want_lu_reject_cause = 0x42,
+		.want_cm_reject_cause = 0x23,
 	},
 	{
 		/* deny by bsc rule */
@@ -769,8 +838,27 @@
 		.result = -2,
 		.bsc_imsi_deny = "[0-9]*",
 		.contype = NAT_CON_TYPE_LU,
+		.nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.bsc_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.want_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.want_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
 	},
-
+	{
+		/* deny by bsc rule */
+		.data = bss_lu,
+		.length = sizeof(bss_lu),
+		.result = -2,
+		.bsc_imsi_deny = "[0-9]*",
+		.contype = NAT_CON_TYPE_LU,
+		.nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED,
+		.bsc_cm_reject_cause = 0x42,
+		.bsc_lu_reject_cause = 0x23,
+		.want_lu_reject_cause = 0x23,
+		.want_cm_reject_cause = 0x42,
+	},
 };
 
 static void test_cr_filter()
@@ -795,11 +883,20 @@
 	bsc_entry = bsc_nat_acc_lst_entry_create(bsc_lst);
 	nat_entry = bsc_nat_acc_lst_entry_create(nat_lst);
 
+	/* test the default value as we are going to overwrite it */
+	OSMO_ASSERT(bsc_entry->cm_reject_cause == GSM48_REJECT_PLMN_NOT_ALLOWED);
+	OSMO_ASSERT(bsc_entry->lu_reject_cause == GSM48_REJECT_PLMN_NOT_ALLOWED);
+
 	for (i = 0; i < ARRAY_SIZE(cr_filter); ++i) {
 		char *imsi;
 		msgb_reset(msg);
 		copy_to_msg(msg, cr_filter[i].data, cr_filter[i].length);
 
+		bsc_entry->cm_reject_cause = cr_filter[i].bsc_cm_reject_cause;
+		bsc_entry->lu_reject_cause = cr_filter[i].bsc_lu_reject_cause;
+		nat_entry->cm_reject_cause = cr_filter[i].nat_cm_reject_cause;
+		nat_entry->lu_reject_cause = cr_filter[i].nat_lu_reject_cause;
+
 		if (gsm_parse_reg(nat_entry, &nat_entry->imsi_deny_re, &nat_entry->imsi_deny,
 			      cr_filter[i].nat_imsi_deny ? 1 : 0,
 			      &cr_filter[i].nat_imsi_deny) != 0)
@@ -826,6 +923,10 @@
 			abort();
 		}
 
+
+		OSMO_ASSERT(cause.cm_reject_cause == cr_filter[i].want_cm_reject_cause);
+		OSMO_ASSERT(cause.lu_reject_cause == cr_filter[i].want_lu_reject_cause);
+
 		if (contype != cr_filter[i].contype) {
 			printf("FAIL: Wrong contype %d for test %d.\n", res, contype);
 			abort();