rlc: Make the RLC types only operate on the BSN

The code has an internal optimization to only use window_size
space. This means that the caller needed to know that only half
of the size was used. Change the API to work on the BSN and do
the mapping internally. The compiler should have plenty of
opportunity to propagate the constant(s) but this has not been
verified.
diff --git a/src/encoding.cpp b/src/encoding.cpp
index 13390b9..085e7c3 100644
--- a/src/encoding.cpp
+++ b/src/encoding.cpp
@@ -363,7 +363,7 @@
 
 	uint8_t rbb = 0;
 	uint16_t i, bbn;
-	uint16_t mod_sns_half = (tbf->sns() >> 1) - 1;
+	uint16_t mod_sns = (tbf->sns() - 1);
 	char bit;
 
 	LOGP(DRLCMACUL, LOGL_DEBUG, "Encoding Ack/Nack for %s "
@@ -383,8 +383,8 @@
 	block->u.Packet_Uplink_Ack_Nack.u.PU_AckNack_GPRS_Struct.Ack_Nack_Description.FINAL_ACK_INDICATION     = final;           // FINAL ACK INDICATION
 	block->u.Packet_Uplink_Ack_Nack.u.PU_AckNack_GPRS_Struct.Ack_Nack_Description.STARTING_SEQUENCE_NUMBER = tbf->dir.ul.window.v_r(); // STARTING_SEQUENCE_NUMBER
 	// RECEIVE_BLOCK_BITMAP
-	for (i = 0, bbn = (tbf->dir.ul.window.v_r() - 64) & mod_sns_half; i < 64;
-	     i++, bbn = (bbn + 1) & mod_sns_half) {
+	for (i = 0, bbn = (tbf->dir.ul.window.v_r() - 64) & mod_sns; i < 64;
+	     i++, bbn = (bbn + 1) & mod_sns) {
 		bit = tbf->dir.ul.v_n.state(bbn);
 		show_v_n[i] = bit;
 		if (bit == 'R')
diff --git a/src/rlc.cpp b/src/rlc.cpp
index dc5cf8b..915da87 100644
--- a/src/rlc.cpp
+++ b/src/rlc.cpp
@@ -49,8 +49,7 @@
 int gprs_rlc_v_b::resend_needed(const gprs_rlc_dl_window &w)
 {
 	for (uint16_t bsn = w.v_a(); bsn != w.v_s(); bsn = (bsn + 1) & w.mod_sns()) {
-		uint16_t index = bsn & w.mod_sns_half();
-		if (is_nacked(index) || is_resend(index))
+		if (is_nacked(bsn) || is_resend(bsn))
 			return bsn;
 	}
 
@@ -62,10 +61,9 @@
 	int resend = 0;
 
 	for (uint16_t bsn = w.v_a(); bsn != w.v_s(); bsn = (bsn + 1) & w.mod_sns()) {
-		uint16_t index = bsn & w.mod_sns_half();
-		if (is_unacked(index)) {
+		if (is_unacked(bsn)) {
 			/* mark to be re-send */
-			mark_resend(index);
+			mark_resend(bsn);
 			resend += 1;
 		}
 	}
@@ -79,8 +77,7 @@
 	uint16_t bsn;
 
 	for (bsn = w.v_a(); bsn != w.v_s(); bsn = (bsn + 1) & w.mod_sns()) {
-		uint16_t index = bsn & w.mod_sns_half();
-		if (!is_acked(index))
+		if (!is_acked(bsn))
 			unacked += 1;
 	}
 
@@ -101,12 +98,12 @@
 
 		if (show_rbb[i] == '1') {
 			LOGP(DRLCMACDL, LOGL_DEBUG, "- got ack for BSN=%d\n", bsn);
-			if (!is_acked(bsn & w.mod_sns_half()))
+			if (!is_acked(bsn))
 				*received += 1;
-			mark_acked(bsn & w.mod_sns_half());
+			mark_acked(bsn);
 		} else {
 			LOGP(DRLCMACDL, LOGL_DEBUG, "- got NACK for BSN=%d\n", bsn);
-			mark_nacked(bsn & w.mod_sns_half());
+			mark_nacked(bsn);
 			bts->rlc_nacked();
 			*lost += 1;
 		}
@@ -120,9 +117,8 @@
 	int moved = 0;
 
 	for (i = 0, bsn = w.v_a(); bsn != w.v_s(); i++, bsn = (bsn + 1) & w.mod_sns()) {
-		uint16_t index = bsn & w.mod_sns_half();
-		if (is_acked(index)) {
-			mark_invalid(index);
+		if (is_acked(bsn)) {
+			mark_invalid(bsn);
 			moved += 1;
 		} else
 			break;
@@ -137,7 +133,7 @@
 	uint16_t bsn;
 
 	for (i = 0, bsn = w.v_a(); bsn != w.v_s(); i++, bsn = (bsn + 1) & w.mod_sns()) {
-		uint16_t index = bsn & w.mod_sns_half();
+		uint16_t index = bsn & mod_sns_half();
 		show_v_b[i] = m_v_b[index];
 		if (show_v_b[i] == 0)
 			show_v_b[i] = ' ';
@@ -159,7 +155,7 @@
 	if (offset_v_r < (sns() >> 1)) {
 		while (offset_v_r--) {
 			if (offset_v_r) /* all except the received block */
-				v_n->mark_missing(v_r() & mod_sns_half());
+				v_n->mark_missing(v_r());
 			raise_v_r(1);
 		}
 		LOGP(DRLCMACUL, LOGL_DEBUG, "- Raising V(R) to %d\n", v_r());
@@ -175,8 +171,7 @@
 	uint16_t count = 0;
 
 	while (v_q() != v_r()) {
-		uint16_t index = v_q() & mod_sns_half();
-		if (!v_n->is_received(index))
+		if (!v_n->is_received(v_q()))
 			break;
 		LOGP(DRLCMACUL, LOGL_DEBUG, "- Taking block %d out, raising "
 			"V(Q) to %d\n", v_q(), (v_q() + 1) & mod_sns());
diff --git a/src/rlc.h b/src/rlc.h
index b85b33e..0ecce40 100644
--- a/src/rlc.h
+++ b/src/rlc.h
@@ -28,6 +28,12 @@
 class BTS;
 struct gprs_rlc_v_n;
 
+
+static inline uint16_t mod_sns_half()
+{
+	return (RLC_MAX_SNS / 2) - 1;
+}
+
 struct gprs_rlc_data {
 	uint8_t *prepare(size_t block_data_length);
 	void put_data(const uint8_t *data, size_t len);
@@ -43,7 +49,8 @@
  * the routines to manipulate these arrays.
  */
 struct gprs_rlc {
-	gprs_rlc_data blocks[RLC_MAX_SNS/2];
+	gprs_rlc_data *block(int bsn);
+	gprs_rlc_data m_blocks[RLC_MAX_SNS/2];
 };
 
 
@@ -56,7 +63,6 @@
  */
 struct gprs_rlc_dl_window {
 	const uint16_t mod_sns() const;
-	const uint16_t mod_sns_half() const;
 	const uint16_t sns() const;
 	const uint16_t ws() const;
 
@@ -68,7 +74,6 @@
 
 	const uint16_t v_s() const;
 	const uint16_t v_s_mod(int offset) const;
-	const uint16_t v_s_mod_half(int offset) const;
 	const uint16_t v_a() const;
 	const int16_t distance() const;
 
@@ -78,7 +83,6 @@
 
 struct gprs_rlc_ul_window {
 	const uint16_t mod_sns() const;
-	const uint16_t mod_sns_half() const;
 	const uint16_t sns() const;
 	const uint16_t ws() const;
 
@@ -112,24 +116,24 @@
 	int count_unacked(const gprs_rlc_dl_window& window);
 
 	/* Check for an individual frame */
-	bool is_unacked(int index) const;
-	bool is_nacked(int index) const;
-	bool is_acked(int index) const;
-	bool is_resend(int index) const;
-	bool is_invalid(int index) const;
+	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 index);
-	void mark_nacked(int index);
-	void mark_acked(int index);
-	void mark_resend(int index);
-	void mark_invalid(int index);
+	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 index, const char state) const;
-	void mark(int index, const char state);
+	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 */
 };
@@ -137,13 +141,15 @@
 struct gprs_rlc_v_n {
 	void reset();
 
-	void mark_received(int index);
-	void mark_missing(int index);
+	void mark_received(int bsn);
+	void mark_missing(int bsn);
 
-	bool is_received(int index) const;
+	bool is_received(int bsn) const;
 
-	char state(int index) const;
+	char state(int bsn) const;
 private:
+	bool is_state(int bsn, const char state) const;
+	void mark(int bsn, const char state);
 	char m_v_n[RLC_MAX_SNS/2]; /* receive state array */
 };
 
@@ -181,75 +187,75 @@
 } __attribute__ ((packed));
 }
 
-inline bool gprs_rlc_v_b::is_state(int index, const char type) const
+inline bool gprs_rlc_v_b::is_state(int bsn, const char type) const
 {
-	return m_v_b[index] == type;
+	return m_v_b[bsn & mod_sns_half()] == type;
 }
 
-inline void gprs_rlc_v_b::mark(int index, const char type)
+inline void gprs_rlc_v_b::mark(int bsn, const char type)
 {
-	m_v_b[index] = type;
+	m_v_b[bsn & mod_sns_half()] = type;
 }
 
-inline bool gprs_rlc_v_b::is_nacked(int index) const
+inline bool gprs_rlc_v_b::is_nacked(int bsn) const
 {
-	return is_state(index, 'N');
+	return is_state(bsn, 'N');
 }
 
-inline bool gprs_rlc_v_b::is_acked(int index) const
+inline bool gprs_rlc_v_b::is_acked(int bsn) const
 {
-	return is_state(index, 'A');
+	return is_state(bsn, 'A');
 }
 
-inline bool gprs_rlc_v_b::is_unacked(int index) const
+inline bool gprs_rlc_v_b::is_unacked(int bsn) const
 {
-	return is_state(index, 'U');
+	return is_state(bsn, 'U');
 }
 
-inline bool gprs_rlc_v_b::is_resend(int index) const
+inline bool gprs_rlc_v_b::is_resend(int bsn) const
 {
-	return is_state(index, 'X');
+	return is_state(bsn, 'X');
 }
 
-inline bool gprs_rlc_v_b::is_invalid(int index) const
+inline bool gprs_rlc_v_b::is_invalid(int bsn) const
 {
-	return is_state(index, 'I');
+	return is_state(bsn, 'I');
 }
 
-inline void gprs_rlc_v_b::mark_resend(int index)
+inline void gprs_rlc_v_b::mark_resend(int bsn)
 {
-	return mark(index, 'X');
+	return mark(bsn, 'X');
 }
 
-inline void gprs_rlc_v_b::mark_unacked(int index)
+inline void gprs_rlc_v_b::mark_unacked(int bsn)
 {
-	return mark(index, 'U');
+	return mark(bsn, 'U');
 }
 
-inline void gprs_rlc_v_b::mark_acked(int index)
+inline void gprs_rlc_v_b::mark_acked(int bsn)
 {
-	return mark(index, 'A');
+	return mark(bsn, 'A');
 }
 
-inline void gprs_rlc_v_b::mark_nacked(int index)
+inline void gprs_rlc_v_b::mark_nacked(int bsn)
 {
-	return mark(index, 'N');
+	return mark(bsn, 'N');
 }
 
-inline void gprs_rlc_v_b::mark_invalid(int index)
+inline void gprs_rlc_v_b::mark_invalid(int bsn)
 {
-	return mark(index, 'I');
+	return mark(bsn, 'I');
 }
 
 
 inline const uint16_t gprs_rlc_dl_window::sns() const
 {
-	return 128;
+	return RLC_MAX_SNS;
 }
 
 inline const uint16_t gprs_rlc_dl_window::ws() const
 {
-	return 64;
+	return RLC_MAX_WS;
 }
 
 inline const uint16_t gprs_rlc_dl_window::mod_sns() const
@@ -257,21 +263,11 @@
 	return sns() - 1;
 }
 
-inline const uint16_t gprs_rlc_dl_window::mod_sns_half() const
-{
-	return (sns() >> 1) - 1;
-}
-
 inline const uint16_t gprs_rlc_dl_window::v_s() const
 {
 	return m_v_s;
 }
 
-inline const uint16_t gprs_rlc_dl_window::v_s_mod_half(int offset) const
-{
-	return (m_v_s + offset) & mod_sns_half();
-}
-
 inline const uint16_t gprs_rlc_dl_window::v_s_mod(int offset) const
 {
 	return (m_v_s + offset) & mod_sns();
@@ -320,12 +316,12 @@
 
 inline const uint16_t gprs_rlc_ul_window::sns() const
 {
-	return 128;
+	return RLC_MAX_SNS;
 }
 
 inline const uint16_t gprs_rlc_ul_window::ws() const
 {
-	return 64;
+	return RLC_MAX_WS;
 }
 
 inline const uint16_t gprs_rlc_ul_window::mod_sns() const
@@ -333,11 +329,6 @@
 	return sns() - 1;
 }
 
-inline const uint16_t gprs_rlc_ul_window::mod_sns_half() const
-{
-	return (sns() >> 1) - 1;
-}
-
 inline const uint16_t gprs_rlc_ul_window::v_r() const
 {
 	return m_v_r;
@@ -358,25 +349,40 @@
 	m_v_q = (m_v_q + incr) & mod_sns();
 }
 
-inline void gprs_rlc_v_n::mark_received(int index)
+inline void gprs_rlc_v_n::mark_received(int bsn)
 {
-	m_v_n[index] = 'R';
+	return mark(bsn, 'R');
 }
 
-inline void gprs_rlc_v_n::mark_missing(int index)
+inline void gprs_rlc_v_n::mark_missing(int bsn)
 {
-	m_v_n[index] = 'N';
+	return mark(bsn, 'N');
 }
 
-inline bool gprs_rlc_v_n::is_received(int index) const
+inline bool gprs_rlc_v_n::is_received(int bsn) const
 {
-	return m_v_n[index] == 'R';
+	return is_state(bsn, 'R');
 }
 
-inline char gprs_rlc_v_n::state(int index) const
+inline bool gprs_rlc_v_n::is_state(int bsn, const char type) const
 {
-	char bit = m_v_n[index];
+	return m_v_n[bsn & mod_sns_half()] == type;
+}
+
+inline void gprs_rlc_v_n::mark(int bsn, const char type)
+{
+	m_v_n[bsn & mod_sns_half()] = type;
+}
+
+inline char gprs_rlc_v_n::state(int bsn) const
+{
+	char bit = m_v_n[bsn & mod_sns_half()];
 	if (bit == '\0')
 		return ' ';
 	return bit;
 }
+
+inline gprs_rlc_data *gprs_rlc::block(int bsn)
+{
+	return &m_blocks[bsn & mod_sns_half()];
+}
diff --git a/src/tbf.cpp b/src/tbf.cpp
index cc8effa..3f4da56 100644
--- a/src/tbf.cpp
+++ b/src/tbf.cpp
@@ -839,12 +839,10 @@
 	int resend_bsn = dir.dl.v_b.resend_needed(dir.dl.window);
 	if (resend_bsn >= 0) {
 		LOGP(DRLCMACDL, LOGL_DEBUG, "- Resending BSN %d\n", resend_bsn);
-
-		uint16_t index = resend_bsn & dir.dl.window.mod_sns_half();
 		/* re-send block with negative aknowlegement */
-		dir.dl.v_b.mark_unacked(index);
+		dir.dl.v_b.mark_unacked(resend_bsn);
 		bts->rlc_resent();
-		return create_dl_acked_block(fn, ts, index, false);
+		return create_dl_acked_block(fn, ts, resend_bsn, false);
 	}
 
 	/* if the window has stalled, or transfer is complete,
@@ -871,7 +869,7 @@
 			LOGP(DRLCMACDL, LOGL_DEBUG, "- MS acked all blocks, "
 				"so we re-transmit final block!\n");
 			/* we just send final block again */
-			int16_t index = dir.dl.window.v_s_mod_half(-1);
+			int16_t index = dir.dl.window.v_s_mod(-1);
 			bts->rlc_resent();
 			return create_dl_acked_block(fn, ts, index, false);
 		}
@@ -886,8 +884,7 @@
 				"There are no unacknowledged blocks, but V(A) "
 				" != V(S). PLEASE FIX!\n");
 			/* we just send final block again */
-			int16_t index = dir.dl.window.v_s_mod_half(-1);
-			bts->rlc_resent();
+			int16_t index = dir.dl.window.v_s_mod(-1);
 			return create_dl_acked_block(fn, ts, index, false);
 		}
 		goto do_resend;
@@ -901,10 +898,11 @@
 	struct rlc_dl_header *rh;
 	struct rlc_li_field *li;
 	struct msgb *msg;
-	uint16_t index;
 	uint8_t *delimiter, *data, *e_pointer;
 	uint16_t space, chunk;
+	gprs_rlc_data *rlc_data;
 	bool first_fin_ack = false;
+	const uint16_t bsn = dir.dl.window.v_s();
 
 	LOGP(DRLCMACDL, LOGL_DEBUG, "- Sending new block at BSN %d\n",
 		dir.dl.window.v_s());
@@ -921,8 +919,8 @@
 	const uint8_t block_data_len = gprs_rlcmac_cs[cs].block_data;
 
 	/* now we still have untransmitted LLC data, so we fill mac block */
-	index = dir.dl.window.v_s_mod_half(0);
-	data = m_rlc.blocks[index].prepare(block_data_len);
+	rlc_data = m_rlc.block(bsn);
+	data = rlc_data->prepare(block_data_len);
 
 	rh = (struct rlc_dl_header *)data;
 	rh->pt = 0; /* Data Block */
@@ -931,7 +929,7 @@
 	rh->pr = 0; /* FIXME: power reduction */
 	rh->tfi = m_tfi; /* TFI */
 	rh->fbi = 0; /* Final Block Indicator, set late, if true */
-	rh->bsn = dir.dl.window.v_s(); /* Block Sequence Number */
+	rh->bsn = bsn; /* Block Sequence Number */
 	rh->e = 0; /* Extension bit, maybe set later */
 	e_pointer = data + 2; /* points to E of current chunk */
 	data += sizeof(*rh);
@@ -1052,14 +1050,14 @@
 		break;
 	}
 	LOGP(DRLCMACDL, LOGL_DEBUG, "data block: %s\n",
-		osmo_hexdump(m_rlc.blocks[index].block, block_length));
+		osmo_hexdump(rlc_data->block, block_length));
 #warning "move this up?"
-	m_rlc.blocks[index].len = block_length;
+	rlc_data->len = block_length;
 	/* raise send state and set ack state array */
-	dir.dl.v_b.mark_unacked(index);
+	dir.dl.v_b.mark_unacked(bsn);
 	dir.dl.window.increment_send();
 
-	return create_dl_acked_block(fn, ts, index, first_fin_ack);
+	return create_dl_acked_block(fn, ts, bsn, first_fin_ack);
 }
 
 struct msgb *gprs_rlcmac_tbf::create_dl_acked_block(
@@ -1072,8 +1070,8 @@
 	uint8_t len;
 
 	/* get data and header from current block */
-	data = m_rlc.blocks[index].block;
-	len = m_rlc.blocks[index].len;
+	data = m_rlc.block(index)->block;
+	len = m_rlc.block(index)->len;
 	rh = (struct rlc_dl_header *)data;
 
 	/* Clear Polling, if still set in history buffer */
@@ -1553,12 +1551,10 @@
 
 int gprs_rlcmac_tbf::rcv_data_block_acknowledged(const uint8_t *data, size_t len, int8_t rssi)
 {
-	uint16_t index;
 	struct rlc_ul_header *rh = (struct rlc_ul_header *)data;
 	int rc;
 
 	const uint16_t mod_sns = dir.ul.window.mod_sns();
-	const uint16_t mod_sns_half = dir.ul.window.mod_sns_half();
 	const uint16_t ws = dir.ul.window.ws();
 
 	this->state_flags |= (1 << GPRS_RLCMAC_FLAG_UL_DATA);
@@ -1607,13 +1603,12 @@
 	}
 
 	/* Write block to buffer and set receive state array. */
-	index = rh->bsn & mod_sns_half; /* memory index of block */
-	m_rlc.blocks[index].put_data(data, len);
+	m_rlc.block(rh->bsn)->put_data(data, len);
 	LOGP(DRLCMACUL, LOGL_DEBUG, "- BSN %d storing in window (%d..%d)\n",
 		rh->bsn, dir.ul.window.v_q(),
 		(dir.ul.window.v_q() + ws - 1) & mod_sns);
 
-	dir.ul.v_n.mark_received(index);
+	dir.ul.v_n.mark_received(rh->bsn);
 	dir.ul.window.raise_v_r(rh->bsn, &dir.ul.v_n);
 
 	/* Raise V(Q) if possible, and retrieve LLC frames from blocks.
@@ -1624,15 +1619,15 @@
 
 	/* Retrieve LLC frames from blocks that are ready */
 	for (uint16_t i = 0; i < count; ++i) {
-		uint16_t index = (v_q_beg + i) & mod_sns_half;
-		assemble_forward_llc(&m_rlc.blocks[index]);
+		uint16_t index = (v_q_beg + i) & mod_sns;
+		assemble_forward_llc(m_rlc.block(index));
 	}
 
 	/* Check CV of last frame in buffer */
 	if (this->state_is(GPRS_RLCMAC_FLOW) /* still in flow state */
 	 && this->dir.ul.window.v_q() == this->dir.ul.window.v_r()) { /* if complete */
 		struct rlc_ul_header *last_rh = (struct rlc_ul_header *)
-			m_rlc.blocks[(this->dir.ul.window.v_r() - 1) & mod_sns_half].block;
+			m_rlc.block((dir.ul.window.v_r() - 1) & mod_sns)->block;
 		LOGP(DRLCMACUL, LOGL_DEBUG, "- No gaps in received block, "
 			"last block: BSN=%d CV=%d\n", last_rh->bsn,
 			last_rh->cv);