bssgp: Use measured leak rate for flow control

The leak rate sent to the SGSN does not reflect the current CS level,
lost frames, and control message overhead. So the SGSN cannot do
proper queue control under non-optimal conditions.

This commit computes the leak rate for the last flow control interval
by computing the maximum theoretical leak rate and basically
substracting control blocks, nacked blocks, and reduced block sizes
due to CS downgrade. By using this approach, the value will by more
stable on low load, where the value will tend to be near the value
derived from the configuration. On full load the transmitted value is
completely derived from the measurements.

Note that the MS default values are no adapted to the adapted BVC
leak rate, since a single MS which has a lower link quality would
otherwise be reducing the rate of another MS with good radio
conditions, which would not make much sense if they did not share any
PDCH.

Sponsored-by: On-Waves ehf
diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp
index aabe8e3..64fbef4 100644
--- a/src/tbf_dl.cpp
+++ b/src/tbf_dl.cpp
@@ -712,7 +712,8 @@
 	return (ssn - 1 - bitnum) & mod_sns;
 }
 
-int gprs_rlcmac_dl_tbf::analyse_errors(char *show_rbb, uint8_t ssn)
+int gprs_rlcmac_dl_tbf::analyse_errors(char *show_rbb, uint8_t ssn,
+	ana_result *res)
 {
 	gprs_rlc_data *rlc_data;
 	uint16_t lost = 0, received = 0, skipped = 0;
@@ -720,9 +721,13 @@
 	memset(info, '.', sizeof(info));
 	info[64] = 0;
 	uint16_t bsn = 0;
+	unsigned received_bytes = 0, lost_bytes = 0;
+	unsigned received_packets = 0, lost_packets = 0;
 
 	/* SSN - 1 is in range V(A)..V(S)-1 */
 	for (int bitpos = 0; bitpos < m_window.ws(); bitpos++) {
+		bool is_received = show_rbb[m_window.ws() - 1 - bitpos] == 'R';
+
 		bsn = bitnum_to_bsn(bitpos, ssn, m_window.mod_sns());
 
 		if (bsn == ((m_window.v_a() - 1) & m_window.mod_sns())) {
@@ -736,6 +741,17 @@
 			continue;
 		}
 
+		/* Get general statistics */
+		if (is_received && !m_window.m_v_b.is_acked(bsn)) {
+			received_packets += 1;
+			received_bytes += rlc_data->len;
+		} else if (!is_received && !m_window.m_v_b.is_nacked(bsn)) {
+			lost_packets += 1;
+			lost_bytes += rlc_data->len;
+		}
+
+		/* Get statistics for current CS */
+
 		if (rlc_data->cs != current_cs()) {
 			/* This block has already been encoded with a different
 			 * CS, so it doesn't help us to decide, whether the
@@ -745,7 +761,7 @@
 			continue;
 		}
 
-		if (show_rbb[m_window.ws() - 1 - bitpos] == 'R') {
+		if (is_received) {
 			if (!m_window.m_v_b.is_acked(bsn)) {
 				received += 1;
 				info[bitpos] = 'R';
@@ -763,6 +779,11 @@
 		name(), m_window.v_a(), m_window.v_s(), lost, received,
 		skipped, bsn, info);
 
+	res->received_packets = received_packets;
+	res->lost_packets = lost_packets;
+	res->received_bytes = received_bytes;
+	res->lost_bytes = lost_bytes;
+
 	if (lost + received <= 1)
 		return -1;
 
@@ -778,6 +799,7 @@
 	char show_v_b[RLC_MAX_SNS + 1];
 	const uint16_t mod_sns = m_window.mod_sns();
 	int error_rate;
+	struct ana_result ana_res;
 
 	Decoding::extract_rbb(rbb, show_rbb);
 	/* show received array in debug (bit 64..1) */
@@ -800,10 +822,10 @@
 		return 1; /* indicate to free TBF */
 	}
 
-	if (bts_data()->cs_adj_enabled && ms()) {
-		error_rate = analyse_errors(show_rbb, ssn);
+	error_rate = analyse_errors(show_rbb, ssn, &ana_res);
+
+	if (bts_data()->cs_adj_enabled && ms())
 		ms()->update_error_rate(this, error_rate);
-	}
 
 	m_window.update(bts, show_rbb, ssn,
 			&lost, &received);
@@ -811,6 +833,10 @@
 	/* report lost and received packets */
 	gprs_rlcmac_received_lost(this, received, lost);
 
+	/* Used to measure the leak rate */
+	gprs_bssgp_update_bytes_received(ana_res.received_bytes,
+		ana_res.received_packets + ana_res.lost_packets);
+
 	/* raise V(A), if possible */
 	m_window.raise(m_window.move_window());