Merge branch 'daniel/controlif'
diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h
index ff4aec1..d78252a 100644
--- a/openbsc/include/openbsc/debug.h
+++ b/openbsc/include/openbsc/debug.h
@@ -35,6 +35,7 @@
 	DLLC,
 	DSNDCP,
 	DNAT,
+	DCTRL,
 	Debug_LastEntry,
 };
 
diff --git a/openbsc/src/libcommon/debug.c b/openbsc/src/libcommon/debug.c
index 1372150..479390c 100644
--- a/openbsc/src/libcommon/debug.c
+++ b/openbsc/src/libcommon/debug.c
@@ -175,6 +175,11 @@
 		.description = "GSM 08.08 NAT/Multipkexer",
 		.enabled = 1, .loglevel = LOGL_NOTICE,
 	},
+	[DCTRL] = {
+		.name = "DCTRL",
+		.description = "Control interface",
+		.enabled = 1, .loglevel = LOGL_NOTICE,
+	},
 };
 
 enum log_filter {
diff --git a/openbsc/src/libctrl/control_if.c b/openbsc/src/libctrl/control_if.c
index 0e625cd..91c69e0 100644
--- a/openbsc/src/libctrl/control_if.c
+++ b/openbsc/src/libctrl/control_if.c
@@ -22,6 +22,7 @@
  */
 
 #include <errno.h>
+#include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -365,7 +366,7 @@
 		return NULL;
 
 	for (i=0;i<ctrg->desc->num_ctr;i++) {
-		counters = talloc_asprintf_append(counters, "\n%s.%u.%s %lu",
+		counters = talloc_asprintf_append(counters, "\n%s.%u.%s %"PRIu64,
 			ctrg->desc->group_name_prefix, ctrg->idx,
 			ctrg->desc->ctr_desc[i].name,
 			get_rate_ctr_value(&ctrg->ctr[i], intv));
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_main.c b/openbsc/src/osmo-bsc/osmo_bsc_main.c
index 2a4ed1a..7d376ef 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_main.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_main.c
@@ -29,6 +29,7 @@
 #include <openbsc/ipaccess.h>
 
 #include <osmocom/core/application.h>
+#include <osmocom/core/linuxlist.h>
 #include <osmocom/core/talloc.h>
 #include <osmocom/gsm/protocol/gsm_12_21.h>
 
@@ -171,18 +172,57 @@
 }
 
 struct location {
+	struct llist_head list;
+	unsigned long age;
+	int valid;
 	double lat;
 	double lon;
 	double height;
-	unsigned long age;
 };
 
-static struct location myloc;
+static LLIST_HEAD(locations);
+
+void cleanup_locations()
+{
+	struct location *myloc, *tmp;
+	int invalpos = 0, i = 0;
+
+	LOGP(DCTRL, LOGL_DEBUG, "Checking position list.\n");
+	llist_for_each_entry_safe(myloc, tmp, &locations, list) {
+		i++;
+		if (i > 3) {
+			LOGP(DCTRL, LOGL_DEBUG, "Deleting old position.\n");
+			llist_del(&myloc->list);
+			talloc_free(myloc);
+		} else if (!myloc->valid) { /* Only capture the newest of subsequent invalid positions */
+			invalpos++;
+			if (invalpos > 1) {
+				LOGP(DCTRL, LOGL_DEBUG, "Deleting subsequent invalid position.\n");
+				invalpos--;
+				i--;
+				llist_del(&myloc->list);
+				talloc_free(myloc);
+			}
+		} else {
+			invalpos = 0;
+		}
+	}
+	LOGP(DCTRL, LOGL_DEBUG, "Found %i positions.\n", i);
+}
 
 CTRL_CMD_DEFINE(net_loc, "location");
 int get_net_loc(struct ctrl_cmd *cmd, void *data)
 {
-	cmd->reply = talloc_asprintf(cmd, "%lu,%f,%f,%f", myloc.age, myloc.lat, myloc.lon, myloc.height);
+	struct location *myloc;
+
+	if (llist_empty(&locations)) {
+		cmd->reply = talloc_asprintf(cmd, "0,0,0,0,0");
+		return CTRL_CMD_REPLY;
+	} else {
+		myloc = llist_entry(locations.next, struct location, list);
+	}
+
+	cmd->reply = talloc_asprintf(cmd, "%lu,%i,%f,%f,%f", myloc->age, myloc->valid, myloc->lat, myloc->lon, myloc->height);
 	if (!cmd->reply) {
 		cmd->reply = "OOM";
 		return CTRL_CMD_ERROR;
@@ -193,24 +233,38 @@
 
 int set_net_loc(struct ctrl_cmd *cmd, void *data)
 {
-	char *saveptr, *lat, *lon, *height, *age, *tmp;
+	char *saveptr, *lat, *lon, *height, *age, *valid, *tmp;
+	struct location *myloc;
 
 	tmp = talloc_strdup(cmd, cmd->value);
 	if (!tmp)
 		goto oom;
 
+	myloc = talloc_zero(tall_bsc_ctx, struct location);
+	if (!myloc) {
+		talloc_free(tmp);
+		goto oom;
+	}
+	INIT_LLIST_HEAD(&myloc->list);
+
 
 	age = strtok_r(tmp, ",", &saveptr);
+	valid = strtok_r(NULL, ",", &saveptr);
 	lat = strtok_r(NULL, ",", &saveptr);
 	lon = strtok_r(NULL, ",", &saveptr);
 	height = strtok_r(NULL, "\0", &saveptr);
 
-	myloc.age = atol(age);
-	myloc.lat = atof(lat);
-	myloc.lon = atof(lon);
-	myloc.height = atof(height);
+	myloc->age = atol(age);
+	myloc->valid = atoi(valid);
+	myloc->lat = atof(lat);
+	myloc->lon = atof(lon);
+	myloc->height = atof(height);
 	talloc_free(tmp);
 
+	/* Add location to the end of the list */
+	llist_add(&myloc->list, &locations);
+	cleanup_locations();
+
 	return get_net_loc(cmd, data);
 oom:
 	cmd->reply = "OOM";
@@ -219,9 +273,9 @@
 
 int verify_net_loc(struct ctrl_cmd *cmd, const char *value, void *data)
 {
-	char *saveptr, *latstr, *lonstr, *heightstr, *agestr, *tmp;
-	int  ret = 0;
+	char *saveptr, *latstr, *lonstr, *heightstr, *agestr, *validstr, *tmp;
 	unsigned long age;
+	int valid;
 	double lat, lon, height;
 
 	tmp = talloc_strdup(cmd, value);
@@ -229,23 +283,27 @@
 		return 1;
 
 	agestr = strtok_r(tmp, ",", &saveptr);
+	validstr = strtok_r(NULL, ",", &saveptr);
 	latstr = strtok_r(NULL, ",", &saveptr);
 	lonstr = strtok_r(NULL, ",", &saveptr);
 	heightstr = strtok_r(NULL, "\0", &saveptr);
 
-	if ((agestr == 0) || (latstr == 0) || (lonstr == 0) || (heightstr == 0))
-		ret = 1;
+	if ((agestr == NULL) || (validstr == NULL) || (latstr == NULL) ||
+			(lonstr == NULL) || (heightstr == NULL))
+		return 1;
 
 	age = atol(agestr);
+	valid = atoi(validstr);
 	lat = atof(latstr);
 	lon = atof(lonstr);
 	height = atof(heightstr);
 	talloc_free(tmp);
 
-	if ((age == 0) || (lat < -90) || (lat > 90) || (lon < -180) || (lon > 180))
+	if ((age == 0) || (lat < -90) || (lat > 90) || (lon < -180) ||
+			(lon > 180) || (valid < 0) || (valid > 2))
 		return 1;
 
-	return ret;
+	return 0;
 }
 
 CTRL_CMD_DEFINE(trx_rf_lock, "rf_locked");