[GPRS] NS: Allow filtering of log messages by NSVC / NSEI
diff --git a/openbsc/src/debug.c b/openbsc/src/debug.c
index 1ef5c73..31694f3 100644
--- a/openbsc/src/debug.c
+++ b/openbsc/src/debug.c
@@ -176,17 +176,24 @@
 enum log_filter {
 	_FLT_ALL = LOG_FILTER_ALL,	/* libosmocore */
 	FLT_IMSI = 1,
+	FLT_NSVC = 1,
 };
 
 static int filter_fn(const struct log_context *ctx,
 		     struct log_target *tar)
 {
 	struct gsm_subscriber *subscr = ctx->ctx[BSC_CTX_SUBSCR];
+	const struct gprs_nsvc *nsvc = ctx->ctx[BSC_CTX_NSVC];
 
 	if ((tar->filter_map & (1 << FLT_IMSI)) != 0
 	    && subscr && strcmp(subscr->imsi, tar->filter_data[FLT_IMSI]) == 0)
 		return 1;
 
+	/* Filter on the NS Virtual Connection */
+	if ((tar->filter_map & (1 << FLT_NSVC)) != 0
+	    && nsvc && (nsvc == tar->filter_data[FLT_NSVC]))
+		return 1;
+
 	return 0;
 }
 
@@ -207,3 +214,15 @@
 		target->filter_data[FLT_IMSI] = NULL;
 	}
 }
+
+void log_set_nsvc_filter(struct log_target *target,
+			 const struct gprs_nsvc *nsvc)
+{
+	if (nsvc) {
+		target->filter_map |= (1 << FLT_NSVC);
+		target->filter_data[FLT_NSVC] = nsvc;
+	} else if (target->filter_data[FLT_NSVC]) {
+		target->filter_map = ~(1 << FLT_NSVC);
+		target->filter_data[FLT_NSVC] = NULL;
+	}
+}
diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c
index 2315f23..ea67112 100644
--- a/openbsc/src/gprs/gprs_ns.c
+++ b/openbsc/src/gprs/gprs_ns.c
@@ -209,6 +209,8 @@
 {
 	int ret;
 
+	log_set_context(BSC_CTX_NSVC, nsvc);
+
 	/* Increment number of Uplink bytes */
 	rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_PKTS_OUT]);
 	rate_ctr_add(&nsvc->ctrg->ctr[NS_CTR_BYTES_OUT], msgb_l2len(msg));
@@ -231,6 +233,8 @@
 	struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS");
 	struct gprs_ns_hdr *nsh;
 
+	log_set_context(BSC_CTX_NSVC, nsvc);
+
 	if (!msg)
 		return -ENOMEM;
 
@@ -249,6 +253,8 @@
 	uint16_t nsvci = htons(nsvc->nsvci);
 	uint16_t nsei = htons(nsvc->nsei);
 
+	log_set_context(BSC_CTX_NSVC, nsvc);
+
 	if (!msg)
 		return -ENOMEM;
 
@@ -274,6 +280,8 @@
 	struct gprs_ns_hdr *nsh;
 	uint16_t nsvci = htons(nsvc->nsvci);
 
+	log_set_context(BSC_CTX_NSVC, nsvc);
+
 	bvci = htons(bvci);
 
 	if (!msg)
@@ -320,6 +328,8 @@
 	struct gprs_ns_hdr *nsh;
 	uint16_t nsvci = htons(nsvc->nsvci);
 
+	log_set_context(BSC_CTX_NSVC, nsvc);
+
 	if (!msg)
 		return -ENOMEM;
 
@@ -342,6 +352,7 @@
 
 int gprs_ns_tx_unblock(struct gprs_nsvc *nsvc)
 {
+	log_set_context(BSC_CTX_NSVC, nsvc);
 	LOGP(DNS, LOGL_INFO, "NSEI=%u Tx NS UNBLOCK (NSVCI=%u)\n",
 		nsvc->nsei, nsvc->nsvci);
 
@@ -350,6 +361,7 @@
 
 int gprs_ns_tx_alive(struct gprs_nsvc *nsvc)
 {
+	log_set_context(BSC_CTX_NSVC, nsvc);
 	LOGP(DNS, LOGL_DEBUG, "NSEI=%u Tx NS ALIVE (NSVCI=%u)\n",
 		nsvc->nsei, nsvc->nsvci);
 
@@ -358,6 +370,7 @@
 
 int gprs_ns_tx_alive_ack(struct gprs_nsvc *nsvc)
 {
+	log_set_context(BSC_CTX_NSVC, nsvc);
 	LOGP(DNS, LOGL_DEBUG, "NSEI=%u Tx NS ALIVE_ACK (NSVCI=%u)\n",
 		nsvc->nsei, nsvc->nsvci);
 
@@ -382,6 +395,7 @@
 	enum ns_timeout tout = timer_mode_tout[mode];
 	unsigned int seconds = nsvc->nsi->timeout[tout];
 
+	log_set_context(BSC_CTX_NSVC, nsvc);
 	DEBUGP(DNS, "NSEI=%u Starting timer in mode %s (%u seconds)\n",
 		nsvc->nsei, get_value_string(timer_mode_strs, mode),
 		seconds);
@@ -399,6 +413,7 @@
 	enum ns_timeout tout = timer_mode_tout[nsvc->timer_mode];
 	unsigned int seconds = nsvc->nsi->timeout[tout];
 
+	log_set_context(BSC_CTX_NSVC, nsvc);
 	DEBUGP(DNS, "NSEI=%u Timer expired in mode %s (%u seconds)\n",
 		nsvc->nsei, get_value_string(timer_mode_strs, nsvc->timer_mode),
 		seconds);
@@ -452,6 +467,7 @@
 	struct gprs_ns_hdr *nsh;
 	uint16_t nsvci, nsei;
 
+	log_set_context(BSC_CTX_NSVC, nsvc);
 	if (!msg)
 		return -ENOMEM;
 
@@ -485,6 +501,7 @@
 			"to NS-VC!\n", msgb_nsei(msg));
 		return -EINVAL;
 	}
+	log_set_context(BSC_CTX_NSVC, nsvc);
 
 	if (!(nsvc->state & NSE_S_ALIVE)) {
 		LOGP(DNS, LOGL_ERROR, "NSEI=%u is not alive, cannot send\n",
@@ -642,6 +659,7 @@
 		if (nsh->pdu_type != NS_PDUT_RESET) {
 			/* Since we have no NSVC, we have to use a fake */
 			nsvc = nsi->unknown_nsvc;
+			log_set_context(BSC_CTX_NSVC, nsvc);
 			LOGP(DNS, LOGL_INFO, "Rejecting NS PDU type 0x%0x "
 				"from %s:%u for non-existing NS-VC\n",
 				nsh->pdu_type, inet_ntoa(saddr->sin_addr),
@@ -668,15 +686,18 @@
 		 * simply have changed addresses, or it is a SGSN */
 		nsvc = nsvc_by_nsei(nsi, nsei);
 		if (!nsvc) {
+			nsvc = nsvc_create(nsi, 0xffff);
+			log_set_context(BSC_CTX_NSVC, nsvc);
 			LOGP(DNS, LOGL_INFO, "Creating NS-VC for BSS at %s:%u\n",
 				inet_ntoa(saddr->sin_addr), ntohs(saddr->sin_port));
-			nsvc = nsvc_create(nsi, 0xffff);
 		}
 		/* Update the remote peer IP address/port */
 		nsvc->ip.bts_addr = *saddr;
 	} else
 		msgb_nsei(msg) = nsvc->nsei;
 
+	log_set_context(BSC_CTX_NSVC, nsvc);
+
 	/* Increment number of Incoming bytes */
 	rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_PKTS_IN]);
 	rate_ctr_add(&nsvc->ctrg->ctr[NS_CTR_BYTES_IN], msgb_l2len(msg));
diff --git a/openbsc/src/gprs/gprs_ns_vty.c b/openbsc/src/gprs/gprs_ns_vty.c
index a945d86..c124d42 100644
--- a/openbsc/src/gprs/gprs_ns_vty.c
+++ b/openbsc/src/gprs/gprs_ns_vty.c
@@ -37,6 +37,7 @@
 #include <openbsc/signal.h>
 #include <openbsc/gprs_ns.h>
 #include <openbsc/gprs_bssgp.h>
+#include <openbsc/telnet_interface.h>
 #include <openbsc/vty.h>
 
 #include <vty/vty.h>
@@ -342,6 +343,38 @@
 	return CMD_SUCCESS;
 }
 
+DEFUN(logging_fltr_nsvc,
+      logging_fltr_nsvc_cmd,
+      "logging filter nsvc (nsei|nsvci) <0-65535>",
+	LOGGING_STR "Filter log messages\n"
+	"Filter based on NS Virtual Connection\n"
+	"Identify NS-VC by NSEI\n"
+	"Identify NS-VC by NSVCI\n"
+	"Numeric identifier\n")
+{
+	struct telnet_connection *conn;
+	struct gprs_nsvc *nsvc;
+	uint16_t id = atoi(argv[1]);
+
+	conn = (struct telnet_connection *) vty->priv;
+	if (!conn->dbg) {
+		vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	if (!strcmp(argv[0], "nsei"))
+		nsvc = nsvc_by_nsei(vty_nsi, id);
+	else
+		nsvc = nsvc_by_nsvci(vty_nsi, id);
+
+	if (!nsvc) {
+		vty_out(vty, "No NS-VC by that identifier%s", VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	log_set_nsvc_filter(conn->dbg, nsvc);
+	return CMD_SUCCESS;
+}
 
 int gprs_ns_vty_init(struct gprs_ns_inst *nsi)
 {
@@ -350,6 +383,7 @@
 	install_element_ve(&show_ns_cmd);
 	install_element_ve(&show_ns_stats_cmd);
 	install_element_ve(&show_nse_cmd);
+	install_element_ve(&logging_fltr_nsvc_cmd);
 
 	install_element(CONFIG_NODE, &cfg_ns_cmd);
 	install_node(&ns_node, config_write_ns);
diff --git a/openbsc/src/vty_interface_cmds.c b/openbsc/src/vty_interface_cmds.c
index a2d3258..687ef4b 100644
--- a/openbsc/src/vty_interface_cmds.c
+++ b/openbsc/src/vty_interface_cmds.c
@@ -30,8 +30,6 @@
 
 #include <stdlib.h>
 
-#define LOGGING_STR	"Configure log message to this terminal\n"
-
 static void _vty_output(struct log_target *tgt, const char *line)
 {
 	struct vty *vty = tgt->tgt_vty.vty;