osmux: send osmux stats in MGCP DLCX responses

This allows us to know what number of messages and bytes has been
received per active osmux endpoint.

Note that an Osmux message is composed of several chunks. Each chunk
contains an osmux header plus several voice data frames.

 P: PS=385, OS=11188, PR=195, OR=5655, PL=0, JI=49
 X-Osmo-CP: EC TIS=0, TOS=0, TIR=0, TOR=0
 X-Osmux-ST: CR=51, BR=3129

The new 'X-Osmux-ST:' notifies the received chunks and bytes.
diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h
index 34c3d97..3bccb39 100644
--- a/openbsc/include/openbsc/mgcp_internal.h
+++ b/openbsc/include/openbsc/mgcp_internal.h
@@ -190,6 +190,11 @@
 		struct osmux_in_handle *in;
 		/* handle to unbatch messages */
 		struct osmux_out_handle out;
+		/* statistics */
+		struct {
+			uint32_t chunks;
+			uint32_t octets;
+		} stats;
 	} osmux;
 };
 
diff --git a/openbsc/src/libmgcp/mgcp_osmux.c b/openbsc/src/libmgcp/mgcp_osmux.c
index 0fa7b45..d5e671d 100644
--- a/openbsc/src/libmgcp/mgcp_osmux.c
+++ b/openbsc/src/libmgcp/mgcp_osmux.c
@@ -261,6 +261,8 @@
 	return msg;
 }
 
+#define osmux_chunk_length(msg, rem) (rem - msg->len);
+
 int osmux_read_from_bsc_nat_cb(struct osmo_fd *ofd, unsigned int what)
 {
 	struct msgb *msg;
@@ -268,6 +270,7 @@
 	struct llist_head list;
 	struct sockaddr_in addr;
 	struct mgcp_config *cfg = ofd->data;
+	uint32_t rem;
 
 	msg = osmux_recv(ofd, &addr);
 	if (!msg)
@@ -277,6 +280,7 @@
 	if (msg->data[0] == MGCP_DUMMY_LOAD)
 		goto out;
 
+	rem = msg->len;
 	while((osmuxh = osmux_xfrm_output_pull(msg)) != NULL) {
 		struct mgcp_endpoint *endp;
 
@@ -289,6 +293,10 @@
 			     osmuxh->circuit_id);
 			goto out;
 		}
+		endp->osmux.stats.octets += osmux_chunk_length(msg, rem);
+		endp->osmux.stats.chunks++;
+		rem = msg->len;
+
 		osmux_xfrm_output(osmuxh, &endp->osmux.out, &list);
 		osmux_tx_sched(&list, scheduled_tx_bts_cb, endp);
 	}
@@ -355,6 +363,7 @@
 	struct llist_head list;
 	struct sockaddr_in addr;
 	struct mgcp_config *cfg = ofd->data;
+	uint32_t rem;
 
 	msg = osmux_recv(ofd, &addr);
 	if (!msg)
@@ -364,6 +373,7 @@
 	if (msg->data[0] == MGCP_DUMMY_LOAD)
 		return osmux_handle_dummy(cfg, &addr, msg);
 
+	rem = msg->len;
 	while((osmuxh = osmux_xfrm_output_pull(msg)) != NULL) {
 		struct mgcp_endpoint *endp;
 
@@ -376,6 +386,10 @@
 			     osmuxh->circuit_id);
 			goto out;
 		}
+		endp->osmux.stats.octets += osmux_chunk_length(msg, rem);
+		endp->osmux.stats.chunks++;
+		rem = msg->len;
+
 		osmux_xfrm_output(osmuxh, &endp->osmux.out, &list);
 		osmux_tx_sched(&list, scheduled_tx_net_cb, endp);
 	}
diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c
index a728b67..79422fe 100644
--- a/openbsc/src/libmgcp/mgcp_protocol.c
+++ b/openbsc/src/libmgcp/mgcp_protocol.c
@@ -1745,12 +1745,24 @@
 	size -= nchars;
 
 	/* Error Counter */
-	snprintf(msg, size,
-		 "\r\nX-Osmo-CP: EC TIS=%u, TOS=%u, TIR=%u, TOR=%u",
-		 endp->net_state.in_stream.err_ts_counter,
-		 endp->net_state.out_stream.err_ts_counter,
-		 endp->bts_state.in_stream.err_ts_counter,
-		 endp->bts_state.out_stream.err_ts_counter);
+	nchars = snprintf(msg, size,
+			  "\r\nX-Osmo-CP: EC TIS=%u, TOS=%u, TIR=%u, TOR=%u",
+			  endp->net_state.in_stream.err_ts_counter,
+			  endp->net_state.out_stream.err_ts_counter,
+			  endp->bts_state.in_stream.err_ts_counter,
+			  endp->bts_state.out_stream.err_ts_counter);
+	if (nchars < 0 || nchars >= size)
+		goto truncate;
+
+	msg += nchars;
+	size -= nchars;
+
+	if (endp->osmux.state == OSMUX_STATE_ENABLED) {
+		snprintf(msg, size,
+			 "\r\nX-Osmux-ST: CR=%u, BR=%u",
+			 endp->osmux.stats.chunks,
+			 endp->osmux.stats.octets);
+	}
 truncate:
 	msg[size - 1] = '\0';
 }