[RRLP] make RRLP mode configurable from config file

We now support different RRLP modes (including "none" to disable RRLP),
you can configure it via "rrlp mode" in the "network" section of
openbsc.cfg.
diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c
index fef1127..cdaba9e 100644
--- a/openbsc/src/gsm_data.c
+++ b/openbsc/src/gsm_data.c
@@ -367,3 +367,26 @@
 	return gsm_auth_policy_names[policy];
 }
 
+static const char *rrlp_mode_names[] = {
+	[RRLP_MODE_NONE] = "none",
+	[RRLP_MODE_MS_BASED] = "ms-based",
+	[RRLP_MODE_MS_PREF] = "ms-preferred",
+	[RRLP_MODE_ASS_PREF] = "ass-preferred",
+};
+
+enum rrlp_mode rrlp_mode_parse(const char *arg)
+{
+	int i;
+	for (i = 0; i < ARRAY_SIZE(rrlp_mode_names); i++) {
+		if (!strcmp(arg, rrlp_mode_names[i]))
+			return i;
+	}
+	return RRLP_MODE_NONE;
+}
+
+const char *rrlp_mode_name(enum rrlp_mode mode)
+{
+	if (mode > ARRAY_SIZE(rrlp_mode_names))
+		return "none";
+	return rrlp_mode_names[mode];
+}
diff --git a/openbsc/src/rrlp.c b/openbsc/src/rrlp.c
index 523b53f..60ce750 100644
--- a/openbsc/src/rrlp.c
+++ b/openbsc/src/rrlp.c
@@ -1,4 +1,4 @@
-
+/* Radio Resource LCS (Location) Protocol, GMS TS 04.31 */
 
 /* (C) 2009 by Harald Welte <laforge@gnumonks.org>
  *
@@ -28,9 +28,42 @@
 #include <openbsc/gsm_subscriber.h>
 #include <openbsc/chan_alloc.h>
 
-/* RRLP MS based position request */
+/* RRLP msPositionReq, nsBased,
+ *	Accuracy=60, Method=gps, ResponseTime=2, oneSet */
 static const u_int8_t ms_based_pos_req[] = { 0x40, 0x01, 0x78, 0xa8 };
 
+/* RRLP msPositionReq, msBasedPref,
+	Accuracy=60, Method=gpsOrEOTD, ResponseTime=5, multipleSets */
+static const u_int8_t ms_pref_pos_req[]  = { 0x40, 0x02, 0x79, 0x50 };
+
+/* RRLP msPositionReq, msAssistedPref,
+	Accuracy=60, Method=gpsOrEOTD, ResponseTime=5, multipleSets */
+static const u_int8_t ass_pref_pos_req[] = { 0x40, 0x03, 0x79, 0x50 };
+
+static int send_rrlp_req(struct gsm_lchan *lchan)
+{
+	struct gsm_network *net = lchan->ts->trx->bts->network;
+	const u_int8_t *req;
+
+	switch (net->rrlp.mode) {
+	case RRLP_MODE_MS_BASED:
+		req = ms_based_pos_req;
+		break;
+	case RRLP_MODE_MS_PREF:
+		req = ms_pref_pos_req;
+		break;
+	case RRLP_MODE_ASS_PREF:
+		req = ass_pref_pos_req;
+		break;
+	case RRLP_MODE_NONE:
+	default:
+		return 0;
+	}
+
+	return gsm48_send_rr_app_info(lchan, 0x00,
+				      sizeof(ms_based_pos_req), req);
+}
+
 static int subscr_sig_cb(unsigned int subsys, unsigned int signal,
 			 void *handler_data, void *signal_data)
 {
@@ -44,8 +77,7 @@
 		lchan = lchan_for_subscr(subscr);
 		if (!lchan)
 			break;
-		gsm48_send_rr_app_info(lchan, 0x00, sizeof(ms_based_pos_req),
-					ms_based_pos_req);
+		send_rrlp_req(lchan);
 		break;
 	}
 	return 0;
@@ -59,9 +91,7 @@
 	switch (signal) {
 	case S_PAGING_COMPLETED:
 		/* A subscriber has attached. */
-		gsm48_send_rr_app_info(psig_data->lchan, 0x00, 
-					sizeof(ms_based_pos_req),
-					ms_based_pos_req);
+		send_rrlp_req(psig_data->lchan);
 		break;
 	}
 	return 0;
diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c
index 529b0d4..adef148 100644
--- a/openbsc/src/vty_interface.c
+++ b/openbsc/src/vty_interface.c
@@ -91,6 +91,8 @@
 		VTY_NEWLINE);
 	vty_out(vty, "  NECI (TCH/H): %u%s", net->neci,
 		VTY_NEWLINE);
+	vty_out(vty, "  RRLP Mode: %s%s", rrlp_mode_name(net->rrlp.mode),
+		VTY_NEWLINE);
 }
 
 DEFUN(show_net, show_net_cmd, "show network",
@@ -289,6 +291,8 @@
 		gsmnet->reject_cause, VTY_NEWLINE);
 	vty_out(vty, " encryption a5 %u%s", gsmnet->a5_encryption, VTY_NEWLINE);
 	vty_out(vty, " neci %u%s", gsmnet->neci, VTY_NEWLINE);
+	vty_out(vty, " rrlp mode %s%s", rrlp_mode_name(gsmnet->rrlp.mode),
+		VTY_NEWLINE);
 	vty_out(vty, " timer t3101 %u%s", gsmnet->T3101, VTY_NEWLINE);
 	vty_out(vty, " timer t3103 %u%s", gsmnet->T3103, VTY_NEWLINE);
 	vty_out(vty, " timer t3105 %u%s", gsmnet->T3105, VTY_NEWLINE);
@@ -838,6 +842,15 @@
 	return CMD_SUCCESS;
 }
 
+DEFUN(cfg_net_rrlp_mode, cfg_net_rrlp_mode_cmd,
+      "rrlp mode (none|ms-based|ms-preferred|ass-preferred)",
+	"Set the Radio Resource Location Protocol Mode")
+{
+	gsmnet->rrlp.mode = rrlp_mode_parse(argv[0]);
+
+	return CMD_SUCCESS;
+}
+
 #define DECLARE_TIMER(number) \
     DEFUN(cfg_net_T##number,					\
       cfg_net_T##number##_cmd,					\
@@ -1344,6 +1357,7 @@
 	install_element(GSMNET_NODE, &cfg_net_reject_cause_cmd);
 	install_element(GSMNET_NODE, &cfg_net_encryption_cmd);
 	install_element(GSMNET_NODE, &cfg_net_neci_cmd);
+	install_element(GSMNET_NODE, &cfg_net_rrlp_mode_cmd);
 	install_element(GSMNET_NODE, &cfg_net_T3101_cmd);
 	install_element(GSMNET_NODE, &cfg_net_T3103_cmd);
 	install_element(GSMNET_NODE, &cfg_net_T3105_cmd);