rlc/tbf: Move v_b into DL window

Move functions resend_needed(), mark_for_resend(), update(),
move_window(), state(), count_unacked() out of v_b directly into the UL
window and provide a function get_state in v_b to access the v_b
elements.
diff --git a/src/rlc.cpp b/src/rlc.cpp
index f3a25b2..0df1655 100644
--- a/src/rlc.cpp
+++ b/src/rlc.cpp
@@ -46,24 +46,24 @@
 		mark_invalid(i);
 }
 
-int gprs_rlc_v_b::resend_needed(const gprs_rlc_dl_window &w)
+int gprs_rlc_dl_window::resend_needed()
 {
-	for (uint16_t bsn = w.v_a(); bsn != w.v_s(); bsn = (bsn + 1) & w.mod_sns()) {
-		if (is_nacked(bsn) || is_resend(bsn))
+	for (uint16_t bsn = v_a(); bsn != v_s(); bsn = (bsn + 1) & mod_sns()) {
+		if (m_v_b.is_nacked(bsn) || m_v_b.is_resend(bsn))
 			return bsn;
 	}
 
 	return -1;
 }
 
-int gprs_rlc_v_b::mark_for_resend(const gprs_rlc_dl_window &w)
+int gprs_rlc_dl_window::mark_for_resend()
 {
 	int resend = 0;
 
-	for (uint16_t bsn = w.v_a(); bsn != w.v_s(); bsn = (bsn + 1) & w.mod_sns()) {
-		if (is_unacked(bsn)) {
+	for (uint16_t bsn = v_a(); bsn != v_s(); bsn = (bsn + 1) & mod_sns()) {
+		if (m_v_b.is_unacked(bsn)) {
 			/* mark to be re-send */
-			mark_resend(bsn);
+			m_v_b.mark_resend(bsn);
 			resend += 1;
 		}
 	}
@@ -71,13 +71,13 @@
 	return resend;
 }
 
-int gprs_rlc_v_b::count_unacked(const gprs_rlc_dl_window &w)
+int gprs_rlc_dl_window::count_unacked()
 {
 	uint16_t unacked = 0;
 	uint16_t bsn;
 
-	for (bsn = w.v_a(); bsn != w.v_s(); bsn = (bsn + 1) & w.mod_sns()) {
-		if (!is_acked(bsn))
+	for (bsn = v_a(); bsn != v_s(); bsn = (bsn + 1) & mod_sns()) {
+		if (!m_v_b.is_acked(bsn))
 			unacked += 1;
 	}
 
@@ -89,40 +89,39 @@
 	return (ssn - 1 - bitnum) & mod_sns;
 }
 
-void gprs_rlc_v_b::update(BTS *bts, char *show_rbb, uint8_t ssn,
-			const gprs_rlc_dl_window &w,
+void gprs_rlc_dl_window::update(BTS *bts, char *show_rbb, uint8_t ssn,
 			uint16_t *lost, uint16_t *received)
 {
 	/* SSN - 1 is in range V(A)..V(S)-1 */
-	for (int bitpos = 0; bitpos < w.ws(); bitpos++) {
-		uint16_t bsn = bitnum_to_bsn(bitpos, ssn, w.mod_sns());
+	for (int bitpos = 0; bitpos < ws(); bitpos++) {
+		uint16_t bsn = bitnum_to_bsn(bitpos, ssn, mod_sns());
 
-		if (bsn == ((w.v_a() - 1) & w.mod_sns()))
+		if (bsn == ((v_a() - 1) & mod_sns()))
 			break;
 
-		if (show_rbb[w.ws() - 1 - bitpos] == 'R') {
+		if (show_rbb[ws() - 1 - bitpos] == 'R') {
 			LOGP(DRLCMACDL, LOGL_DEBUG, "- got ack for BSN=%d\n", bsn);
-			if (!is_acked(bsn))
+			if (!m_v_b.is_acked(bsn))
 				*received += 1;
-			mark_acked(bsn);
+			m_v_b.mark_acked(bsn);
 		} else {
 			LOGP(DRLCMACDL, LOGL_DEBUG, "- got NACK for BSN=%d\n", bsn);
-			mark_nacked(bsn);
+			m_v_b.mark_nacked(bsn);
 			bts->rlc_nacked();
 			*lost += 1;
 		}
 	}
 }
 
-int gprs_rlc_v_b::move_window(const gprs_rlc_dl_window &w)
+int gprs_rlc_dl_window::move_window()
 {
 	int i;
 	uint16_t bsn;
 	int moved = 0;
 
-	for (i = 0, bsn = w.v_a(); bsn != w.v_s(); i++, bsn = (bsn + 1) & w.mod_sns()) {
-		if (is_acked(bsn)) {
-			mark_invalid(bsn);
+	for (i = 0, bsn = v_a(); bsn != v_s(); i++, bsn = (bsn + 1) & mod_sns()) {
+		if (m_v_b.is_acked(bsn)) {
+			m_v_b.mark_invalid(bsn);
 			moved += 1;
 		} else
 			break;
@@ -131,14 +130,14 @@
 	return moved;
 }
 
-void gprs_rlc_v_b::state(char *show_v_b, const gprs_rlc_dl_window &w)
+void gprs_rlc_dl_window::state(char *show_v_b)
 {
 	int i;
 	uint16_t bsn;
 
-	for (i = 0, bsn = w.v_a(); bsn != w.v_s(); i++, bsn = (bsn + 1) & w.mod_sns()) {
+	for (i = 0, bsn = v_a(); bsn != v_s(); i++, bsn = (bsn + 1) & mod_sns()) {
 		uint16_t index = bsn & mod_sns_half();
-		show_v_b[i] = m_v_b[index];
+		show_v_b[i] = m_v_b.get_state(index);
 		if (show_v_b[i] == 0)
 			show_v_b[i] = ' ';
 	}
diff --git a/src/rlc.h b/src/rlc.h
index 158ec3d..316c81f 100644
--- a/src/rlc.h
+++ b/src/rlc.h
@@ -53,6 +53,36 @@
 	gprs_rlc_data m_blocks[RLC_MAX_SNS/2];
 };
 
+/**
+ * TODO: for GPRS/EDGE maybe make sns a template parameter
+ * so we create specialized versions...
+ */
+struct gprs_rlc_v_b {
+	/* Check for an individual frame */
+	bool is_unacked(int bsn) const;
+	bool is_nacked(int bsn) const;
+	bool is_acked(int bsn) const;
+	bool is_resend(int bsn) const;
+	bool is_invalid(int bsn) const;
+	char get_state(int bsn) const;
+
+	/* Mark a RLC frame for something */
+	void mark_unacked(int bsn);
+	void mark_nacked(int bsn);
+	void mark_acked(int bsn);
+	void mark_resend(int bsn);
+	void mark_invalid(int bsn);
+
+	void reset();
+
+
+private:
+	bool is_state(int bsn, const char state) const;
+	void mark(int bsn, const char state);
+
+	char m_v_b[RLC_MAX_SNS/2]; /* acknowledge state array */
+};
+
 
 /**
  * TODO: The UL/DL code could/should share a baseclass but
@@ -77,8 +107,19 @@
 	const uint16_t v_a() const;
 	const int16_t distance() const;
 
+	/* Methods to manage reception */
+	int resend_needed();
+	int mark_for_resend();
+	void update(BTS *bts, char *show_rbb, uint8_t ssn,
+			uint16_t *lost, uint16_t *received);
+	int move_window();
+	void state(char *show_rbb);
+	int count_unacked();
+
 	uint16_t m_v_s;	/* send state */
 	uint16_t m_v_a;	/* ack state */
+
+	gprs_rlc_v_b m_v_b;
 };
 
 struct gprs_rlc_v_n {
@@ -123,43 +164,6 @@
 	gprs_rlc_v_n m_v_n;
 };
 
-/**
- * TODO: for GPRS/EDGE maybe make sns a template parameter
- * so we create specialized versions...
- */
-struct gprs_rlc_v_b {
-	int resend_needed(const gprs_rlc_dl_window& window);
-	int mark_for_resend(const gprs_rlc_dl_window& window);
-	void update(BTS *bts, char *show_rbb, uint8_t ssn,
-			const gprs_rlc_dl_window& window,
-			uint16_t *lost, uint16_t *received);
-	int move_window(const gprs_rlc_dl_window& window);
-	void state(char *show_rbb, const gprs_rlc_dl_window& window);
-	int count_unacked(const gprs_rlc_dl_window& window);
-
-	/* Check for an individual frame */
-	bool is_unacked(int bsn) const;
-	bool is_nacked(int bsn) const;
-	bool is_acked(int bsn) const;
-	bool is_resend(int bsn) const;
-	bool is_invalid(int bsn) const;
-
-	/* Mark a RLC frame for something */
-	void mark_unacked(int bsn);
-	void mark_nacked(int bsn);
-	void mark_acked(int bsn);
-	void mark_resend(int bsn);
-	void mark_invalid(int bsn);
-
-	void reset();
-
-private:
-	bool is_state(int bsn, const char state) const;
-	void mark(int bsn, const char state);
-
-	char m_v_b[RLC_MAX_SNS/2]; /* acknowledge state array */
-};
-
 extern "C" {
 /* TS 04.60  10.2.2 */
 struct rlc_ul_header {
@@ -229,6 +233,11 @@
 	return is_state(bsn, 'I');
 }
 
+inline char gprs_rlc_v_b::get_state(int bsn) const
+{
+	return m_v_b[bsn & mod_sns_half()];
+}
+
 inline void gprs_rlc_v_b::mark_resend(int bsn)
 {
 	return mark(bsn, 'X');
@@ -254,7 +263,6 @@
 	return mark(bsn, 'I');
 }
 
-
 inline const uint16_t gprs_rlc_dl_window::sns() const
 {
 	return RLC_MAX_SNS;
diff --git a/src/tbf.cpp b/src/tbf.cpp
index 6b0e779..5969f0f 100644
--- a/src/tbf.cpp
+++ b/src/tbf.cpp
@@ -834,11 +834,11 @@
 
 do_resend:
 	/* check if there is a block with negative acknowledgement */
-	int resend_bsn = dir.dl.v_b.resend_needed(dir.dl.window);
+	int resend_bsn = dir.dl.window.resend_needed();
 	if (resend_bsn >= 0) {
 		LOGP(DRLCMACDL, LOGL_DEBUG, "- Resending BSN %d\n", resend_bsn);
 		/* re-send block with negative aknowlegement */
-		dir.dl.v_b.mark_unacked(resend_bsn);
+		dir.dl.window.m_v_b.mark_unacked(resend_bsn);
 		bts->rlc_resent();
 		return create_dl_acked_block(fn, ts, resend_bsn, false);
 	}
@@ -873,7 +873,7 @@
 		}
 		
 		/* cycle through all unacked blocks */
-		int resend = dir.dl.v_b.mark_for_resend(dir.dl.window);
+		int resend = dir.dl.window.mark_for_resend();
 
 		/* At this point there should be at least one unacked block
 		 * to be resent. If not, this is an software error. */
@@ -1052,7 +1052,7 @@
 #warning "move this up?"
 	rlc_data->len = block_length;
 	/* raise send state and set ack state array */
-	dir.dl.v_b.mark_unacked(bsn);
+	dir.dl.window.m_v_b.mark_unacked(bsn);
 	dir.dl.window.increment_send();
 
 	return create_dl_acked_block(fn, ts, bsn, first_fin_ack);
@@ -1364,17 +1364,17 @@
 		return 1; /* indicate to free TBF */
 	}
 
-	dir.dl.v_b.update(bts, show_rbb, ssn, dir.dl.window,
+	dir.dl.window.update(bts, show_rbb, ssn,
 			&lost, &received);
 
 	/* report lost and received packets */
 	gprs_rlcmac_received_lost(this, received, lost);
 
 	/* raise V(A), if possible */
-	dir.dl.window.raise(dir.dl.v_b.move_window(dir.dl.window));
+	dir.dl.window.raise(dir.dl.window.move_window());
 
 	/* show receive state array in debug (V(A)..V(S)-1) */
-	dir.dl.v_b.state(show_v_b, dir.dl.window);
+	dir.dl.window.state(show_v_b);
 	LOGP(DRLCMACDL, LOGL_DEBUG, "- V(B): (V(A)=%d)\"%s\""
 		"(V(S)-1=%d)  A=Acked N=Nacked U=Unacked "
 		"X=Resend-Unacked I=Invalid\n",
@@ -1397,7 +1397,7 @@
 
 	LOGP(DRLCMACDL, LOGL_DEBUG, "- Final ACK received.\n");
 	/* range V(A)..V(S)-1 */
-	received = dir.dl.v_b.count_unacked(dir.dl.window);
+	received = dir.dl.window.count_unacked();
 
 	/* report all outstanding packets as received */
 	gprs_rlcmac_received_lost(this, received, 0);
@@ -1721,7 +1721,7 @@
 
 	/* reset rlc states */
 	memset(&dir.dl, 0, sizeof(dir.dl));
-	dir.dl.v_b.reset();
+	dir.dl.window.m_v_b.reset();
 
 	/* keep to flags */
 	state_flags &= GPRS_RLCMAC_FLAG_TO_MASK;
diff --git a/src/tbf.h b/src/tbf.h
index ffcf8d1..02f0b44 100644
--- a/src/tbf.h
+++ b/src/tbf.h
@@ -168,7 +168,6 @@
 	union {
 		struct {
 			gprs_rlc_dl_window window;
-			gprs_rlc_v_b v_b;
 			int32_t tx_counter; /* count all transmitted blocks */
 			uint8_t wait_confirm; /* wait for CCCH IMM.ASS cnf */
 		} dl;
diff --git a/tests/types/TypesTest.cpp b/tests/types/TypesTest.cpp
index 62c6ed2..f48cbc0 100644
--- a/tests/types/TypesTest.cpp
+++ b/tests/types/TypesTest.cpp
@@ -322,9 +322,8 @@
 		char show_rbb[65];
 		BTS dummy_bts;
 		gprs_rlc_dl_window dl_win = { 0, };
-		gprs_rlc_v_b v_b;
 
-		v_b.reset();
+		dl_win.m_v_b.reset();
 
 		OSMO_ASSERT(dl_win.window_empty());
 		OSMO_ASSERT(!dl_win.window_stalled());
@@ -345,7 +344,7 @@
 		Decoding::extract_rbb(rbb_cmp, show_rbb);
 		printf("show_rbb: %s\n", show_rbb);
 
-		v_b.update(&dummy_bts, show_rbb, 35, dl_win, &lost, &recv);
+		dl_win.update(&dummy_bts, show_rbb, 35, &lost, &recv);
 		OSMO_ASSERT(lost == 0);
 		OSMO_ASSERT(recv == 35);