Merge branch 'zecke/feature/rf-lock-exclude'

Exclude a BTS from the RF Lock and allow MO and MT operations on
this BTS. The paging modification has been verified using the FakeBTS
and the handover test. Paging continues to work for the normal case.
diff --git a/openbsc/include/openbsc/gsm_data_shared.h b/openbsc/include/openbsc/gsm_data_shared.h
index 56d62e5..4f9f21f 100644
--- a/openbsc/include/openbsc/gsm_data_shared.h
+++ b/openbsc/include/openbsc/gsm_data_shared.h
@@ -699,6 +699,9 @@
 
 	/* do we use static (user-defined) system information messages? (bitmask) */
 	uint32_t si_mode_static;
+
+	/* exclude the BTS from the global RF Lock handling */
+	int excl_from_rf_lock;
 #endif /* ROLE_BSC */
 	void *role;
 };
diff --git a/openbsc/include/openbsc/osmo_bsc_grace.h b/openbsc/include/openbsc/osmo_bsc_grace.h
index 45d4db8..e9c1a0a 100644
--- a/openbsc/include/openbsc/osmo_bsc_grace.h
+++ b/openbsc/include/openbsc/osmo_bsc_grace.h
@@ -1,6 +1,6 @@
 /*
- * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2010 by On-Waves
+ * (C) 2010-2013 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * (C) 2010-2013 by On-Waves
  * All Rights Reserved
  *
  * This program is free software; you can redistribute it and/or modify
@@ -23,6 +23,9 @@
 
 #include "gsm_data.h"
 
-int bsc_grace_allow_new_connection(struct gsm_network *network);
+struct osmo_msc_data;
+
+int bsc_grace_allow_new_connection(struct gsm_network *net, struct gsm_bts *bts);
+int bsc_grace_paging_request(struct gsm_subscriber *sub, int type, struct osmo_msc_data *msc);
 
 #endif
diff --git a/openbsc/include/openbsc/paging.h b/openbsc/include/openbsc/paging.h
index e1438ba..2a10f4e 100644
--- a/openbsc/include/openbsc/paging.h
+++ b/openbsc/include/openbsc/paging.h
@@ -56,6 +56,8 @@
 /* schedule paging request */
 int paging_request(struct gsm_network *network, struct gsm_subscriber *subscr,
 		   int type, gsm_cbfn *cbfn, void *data);
+int paging_request_bts(struct gsm_bts *bts, struct gsm_subscriber *subscr,
+		int type, gsm_cbfn *cbfn, void *data);
 
 /* stop paging requests */
 void paging_request_stop(struct gsm_bts *bts, struct gsm_subscriber *subscr,
diff --git a/openbsc/src/libbsc/bsc_rf_ctrl.c b/openbsc/src/libbsc/bsc_rf_ctrl.c
index 87bf39d..bd36e18 100644
--- a/openbsc/src/libbsc/bsc_rf_ctrl.c
+++ b/openbsc/src/libbsc/bsc_rf_ctrl.c
@@ -1,8 +1,8 @@
 /* RF Ctl handling socket */
 
 /* (C) 2010 by Harald Welte <laforge@gnumonks.org>
- * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2010 by On-Waves
+ * (C) 2010-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * (C) 2010-2012 by On-Waves
  * All Rights Reserved
  *
  * This program is free software; you can redistribute it and/or modify
@@ -129,6 +129,14 @@
 
 	llist_for_each_entry(bts, &net->bts_list, list) {
 		struct gsm_bts_trx *trx;
+
+		/* Exclude the BTS from the global lock */
+		if (bts->excl_from_rf_lock) {
+			LOGP(DLINP, LOGL_DEBUG,
+				"Excluding BTS(%d) from trx lock.\n", bts->nr);
+			continue;
+		}
+
 		llist_for_each_entry(trx, &bts->trx_list, list) {
 			gsm_trx_lock_rf(trx, lock);
 		}
@@ -176,6 +184,13 @@
 
 	llist_for_each_entry(bts, &conn->rf->gsm_network->bts_list, list) {
 		struct gsm_bts_trx *trx;
+
+		/* Exclude the BTS from the global lock */
+		if (bts->excl_from_rf_lock) {
+			LOGP(DLINP, LOGL_DEBUG,
+				"Excluding BTS(%d) from query.\n", bts->nr);
+			continue;
+		}
 		llist_for_each_entry(trx, &bts->trx_list, list) {
 			if (trx->mo.nm_state.availability == NM_AVSTATE_OK &&
 			    trx->mo.nm_state.operational != NM_OPSTATE_DISABLED) {
@@ -200,6 +215,13 @@
 		if (!bts->oml_link || !is_ipaccess_bts(bts))
 			continue;
 
+		/* Exclude the BTS from the global lock */
+		if (bts->excl_from_rf_lock) {
+			LOGP(DLINP, LOGL_DEBUG,
+				"Excluding BTS(%d) from query.\n", bts->nr);
+			continue;
+		}
+
 		llist_for_each_entry(trx, &bts->trx_list, list) {
 			if (trx->mo.nm_state.availability != NM_AVSTATE_OK ||
 			    trx->mo.nm_state.operational != NM_OPSTATE_ENABLED ||
@@ -233,7 +255,7 @@
 {
 	struct osmo_bsc_rf *rf = (struct osmo_bsc_rf *) _data;
 
-	LOGP(DLINP, LOGL_NOTICE, "Grace timeout. Disabling the TRX.\n");
+	LOGP(DLINP, LOGL_NOTICE, "Grace timeout. Going to disable all BTS/TRX.\n");
 	switch_rf_off(rf);
 }
 
diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c
index e89317d..ec92c18 100644
--- a/openbsc/src/libbsc/bsc_vty.c
+++ b/openbsc/src/libbsc/bsc_vty.c
@@ -580,6 +580,9 @@
 
 	config_write_bts_gprs(vty, bts);
 
+	if (bts->excl_from_rf_lock)
+		vty_out(vty, "  rf-lock-exclude%s", VTY_NEWLINE);
+
 	if (bts->model->config_write_bts)
 		bts->model->config_write_bts(vty, bts);
 
@@ -2443,6 +2446,28 @@
 	return CMD_SUCCESS;
 }
 
+#define EXCL_RFLOCK_STR "Exclude this BTS from the global RF Lock\n"
+
+DEFUN(cfg_bts_excl_rf_lock,
+      cfg_bts_excl_rf_lock_cmd,
+      "rf-lock-exclude",
+      EXCL_RFLOCK_STR)
+{
+	struct gsm_bts *bts = vty->index;
+	bts->excl_from_rf_lock = 1;
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_no_excl_rf_lock,
+      cfg_bts_no_excl_rf_lock_cmd,
+      "no rf-lock-exclude",
+      NO_STR EXCL_RFLOCK_STR)
+{
+	struct gsm_bts *bts = vty->index;
+	bts->excl_from_rf_lock = 0;
+	return CMD_SUCCESS;
+}
+
 #define TRX_TEXT "Radio Transceiver\n"
 
 /* per TRX configuration */
@@ -3037,6 +3062,8 @@
 	install_element(BTS_NODE, &cfg_bts_neigh_mode_cmd);
 	install_element(BTS_NODE, &cfg_bts_neigh_cmd);
 	install_element(BTS_NODE, &cfg_bts_si5_neigh_cmd);
+	install_element(BTS_NODE, &cfg_bts_excl_rf_lock_cmd);
+	install_element(BTS_NODE, &cfg_bts_no_excl_rf_lock_cmd);
 
 	install_element(BTS_NODE, &cfg_trx_cmd);
 	install_node(&trx_node, dummy_config_write);
diff --git a/openbsc/src/libbsc/paging.c b/openbsc/src/libbsc/paging.c
index b731dbc..286c57b 100644
--- a/openbsc/src/libbsc/paging.c
+++ b/openbsc/src/libbsc/paging.c
@@ -1,5 +1,5 @@
 /* Paging helper and manager.... */
-/* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
+/* (C) 2009,2013 by Holger Hans Peter Freyther <zecke@selfish.org>
  * All Rights Reserved
  *
  * This program is free software; you can redistribute it and/or modify
@@ -298,6 +298,26 @@
 	return 0;
 }
 
+int paging_request_bts(struct gsm_bts *bts, struct gsm_subscriber *subscr,
+		int type, gsm_cbfn *cbfn, void *data)
+{
+	int rc;
+
+	/* skip all currently inactive TRX */
+	if (!trx_is_usable(bts->c0))
+		return 0;
+
+	/* maybe it is the first time we use it */
+	paging_init_if_needed(bts);
+
+
+	/* Trigger paging, pass any error to the caller */
+	rc = _paging_request(bts, subscr, type, cbfn, data);
+	if (rc < 0)
+		return rc;
+	return 1;
+}
+
 int paging_request(struct gsm_network *network, struct gsm_subscriber *subscr,
 		   int type, gsm_cbfn *cbfn, void *data)
 {
@@ -314,19 +334,10 @@
 		if (!bts)
 			break;
 
-		/* skip all currently inactive TRX */
-		if (!trx_is_usable(bts->c0))
-			continue;
-
-		/* maybe it is the first time we use it */
-		paging_init_if_needed(bts);
-
-		num_pages++;
-
-		/* Trigger paging, pass any error to caller */
-		rc = _paging_request(bts, subscr, type, cbfn, data);
+		rc = paging_request_bts(bts, subscr, type, cbfn, data);
 		if (rc < 0)
 			return rc;
+		num_pages += rc;
 	} while (1);
 
 	if (num_pages == 0)
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_bssap.c b/openbsc/src/osmo-bsc/osmo_bsc_bssap.c
index 6b8504d..c2c2417 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_bssap.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_bssap.c
@@ -177,7 +177,7 @@
 	subscr->tmsi = tmsi;
 
 	LOGP(DMSC, LOGL_INFO, "Paging request from MSC IMSI: '%s' TMSI: '0x%x/%u' LAC: 0x%x\n", mi_string, tmsi, tmsi, lac);
-	paging_request(msc->network, subscr, chan_needed, NULL, msc);
+	bsc_grace_paging_request(subscr, chan_needed, msc);
 	return 0;
 }
 
@@ -413,8 +413,7 @@
 		ret = bssmap_handle_reset_ack(msc, msg, length);
 		break;
 	case BSS_MAP_MSG_PAGING:
-		if (bsc_grace_allow_new_connection(msc->network))
-			ret = bssmap_handle_paging(msc, msg, length);
+		ret = bssmap_handle_paging(msc, msg, length);
 		break;
 	}
 
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_grace.c b/openbsc/src/osmo-bsc/osmo_bsc_grace.c
index 3f73b50..341971e 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_grace.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_grace.c
@@ -1,6 +1,6 @@
 /*
- * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2010 by On-Waves
+ * (C) 2010-2013 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * (C) 2010-2013 by On-Waves
  * All Rights Reserved
  *
  * This program is free software; you can redistribute it and/or modify
@@ -22,15 +22,59 @@
 #include <openbsc/osmo_bsc_rf.h>
 #include <openbsc/osmo_msc_data.h>
 #include <openbsc/gsm_04_80.h>
+#include <openbsc/gsm_subscriber.h>
+#include <openbsc/paging.h>
 #include <openbsc/signal.h>
 
-int bsc_grace_allow_new_connection(struct gsm_network *network)
+int bsc_grace_allow_new_connection(struct gsm_network *network, struct gsm_bts *bts)
 {
 	if (!network->bsc_data->rf_ctrl)
 		return 1;
+	if (bts->excl_from_rf_lock)
+		return 1;
 	return network->bsc_data->rf_ctrl->policy == S_RF_ON;
 }
 
+/**
+ * Try to not page if everything the cell is not on.
+ */
+int bsc_grace_paging_request(struct gsm_subscriber *subscr, int chan_needed,
+				struct osmo_msc_data *msc)
+{
+	struct gsm_bts *bts = NULL;
+
+	if (!subscr->net->bsc_data->rf_ctrl)
+		goto page;
+	if (subscr->net->bsc_data->rf_ctrl->policy == S_RF_ON)
+		goto page;
+
+	/*
+	 * Check if there is any BTS that is on for the given lac. Start
+	 * with NULL and iterate through all bts.
+	 */
+	do {
+		bts = gsm_bts_by_lac(subscr->net, subscr->lac, bts);
+		if (!bts)
+			break;
+
+		/*
+		 * continue if the BTS is not excluded from the lock
+		 */
+		if (!bts->excl_from_rf_lock)
+			continue;
+
+		/*
+		 * now page on this bts
+		 */
+		paging_request_bts(bts, subscr, chan_needed, NULL, msc);
+	} while (1);
+
+	/* All bts are either off or in the grace period */
+	return 0;
+page:
+	return paging_request(subscr->net, subscr, chan_needed, NULL, msc);
+}
+
 static int handle_sub(struct gsm_lchan *lchan, const char *text)
 {
 	struct gsm_subscriber_connection *conn;
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_sccp.c b/openbsc/src/osmo-bsc/osmo_bsc_sccp.c
index 37eb1b7..3533d6d 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_sccp.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_sccp.c
@@ -190,12 +190,9 @@
 int bsc_create_new_connection(struct gsm_subscriber_connection *conn,
 			      struct osmo_msc_data *msc)
 {
-	struct gsm_network *net;
 	struct osmo_bsc_sccp_con *bsc_con;
 	struct sccp_connection *sccp;
 
-	net = conn->bts->network;
-
 	/* This should not trigger */
 	if (!msc->msc_con->is_authenticated) {
 		LOGP(DMSC, LOGL_ERROR,
@@ -203,7 +200,7 @@
 		return -1;
 	}
 
-	if (!bsc_grace_allow_new_connection(net)) {
+	if (!bsc_grace_allow_new_connection(conn->bts->network, conn->bts)) {
 		LOGP(DMSC, LOGL_NOTICE, "BSC in grace period. No new connections.\n");
 		return -1;
 	}